in source/http_connection.c [267:430]
napi_value aws_napi_http_connection_new(napi_env env, napi_callback_info info) {
struct aws_allocator *allocator = aws_napi_get_allocator();
napi_value result = NULL;
struct aws_tls_connection_options *tls_opts = NULL;
struct aws_http_proxy_options *proxy_opts = NULL;
struct aws_string *host_name = NULL;
struct aws_http_client_connection_options options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
options.allocator = allocator;
/* parse/validate arguments */
napi_value node_args[8];
size_t num_args = AWS_ARRAY_SIZE(node_args);
napi_value *arg = &node_args[0];
AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, node_args, NULL, NULL), {
napi_throw_error(env, NULL, "Failed to retrieve callback information");
return NULL;
});
if (num_args != AWS_ARRAY_SIZE(node_args)) {
napi_throw_error(env, NULL, "http_connection_new needs exactly 7 arguments");
return NULL;
}
napi_value node_bootstrap = *arg++;
struct aws_client_bootstrap *bootstrap = NULL;
struct client_bootstrap_binding *bootstrap_binding = NULL;
napi_get_value_external(env, node_bootstrap, (void **)&bootstrap_binding);
if (bootstrap_binding != NULL) {
bootstrap = aws_napi_get_client_bootstrap(bootstrap_binding);
} else {
bootstrap = aws_napi_get_default_client_bootstrap();
}
/* create node external to hold the connection wrapper, cleanup is required from here on out */
struct http_connection_binding *binding = aws_mem_calloc(allocator, 1, sizeof(struct http_connection_binding));
if (!binding) {
aws_napi_throw_last_error(env);
goto alloc_failed;
}
binding->allocator = allocator;
binding->env = env;
napi_value node_on_setup = *arg++;
if (aws_napi_is_null_or_undefined(env, node_on_setup)) {
napi_throw_error(env, NULL, "on_connection_setup must be a callback");
return NULL;
}
AWS_NAPI_CALL(
env,
aws_napi_create_threadsafe_function(
env,
node_on_setup,
"aws_http_connection_on_connection_setup",
s_http_on_connection_setup_call,
binding,
&binding->on_setup),
{ goto failed_callbacks; });
napi_value node_on_shutdown = *arg++;
if (!aws_napi_is_null_or_undefined(env, node_on_shutdown)) {
AWS_NAPI_CALL(
env,
aws_napi_create_threadsafe_function(
env,
node_on_shutdown,
"aws_http_connection_on_connection_shutdown",
s_http_on_connection_shutdown_call,
binding,
&binding->on_shutdown),
{ goto failed_callbacks; });
}
/* will be owned by tls_options */
napi_value node_host_name = *arg++;
host_name = aws_string_new_from_napi(env, node_host_name);
if (!host_name) {
napi_throw_type_error(env, NULL, "host_name must be a String");
goto argument_error;
}
napi_value node_port = *arg++;
uint32_t port = 0;
AWS_NAPI_CALL(env, napi_get_value_uint32(env, node_port, &port), {
napi_throw_type_error(env, NULL, "port must be a Number");
goto argument_error;
});
options.port = (uint16_t)port;
napi_value node_socket_options = *arg++;
AWS_NAPI_CALL(env, napi_get_value_external(env, node_socket_options, (void **)&options.socket_options), {
napi_throw_error(env, NULL, "Unable to extract socket_options from external");
goto argument_error;
});
napi_value node_tls_opts = *arg++;
if (!aws_napi_is_null_or_undefined(env, node_tls_opts)) {
AWS_NAPI_CALL(env, napi_get_value_external(env, node_tls_opts, (void **)&tls_opts), {
napi_throw_error(env, NULL, "Failed to extract tls_ctx from external");
goto argument_error;
});
}
napi_value node_proxy_opts = *arg++;
if (!aws_napi_is_null_or_undefined(env, node_proxy_opts)) {
struct http_proxy_options_binding *proxy_binding = NULL;
AWS_NAPI_CALL(env, napi_get_value_external(env, node_proxy_opts, (void **)&proxy_binding), {
napi_throw_error(env, NULL, "Failed to extract tls_ctx from external");
goto argument_error;
});
/* proxy_options are copied internally, no need to go nuts on copies */
proxy_opts = &proxy_binding->native;
}
napi_value node_external = NULL;
AWS_NAPI_CALL(
env, napi_create_external(env, binding, s_http_connection_binding_finalize, binding, &node_external), {
napi_throw_error(env, NULL, "Failed to create napi external for http_connection_binding");
goto create_external_failed;
});
AWS_NAPI_CALL(env, napi_create_reference(env, node_external, 1, &binding->node_external), {
napi_throw_error(env, NULL, "Failed to reference node_external");
goto create_external_failed;
});
options.bootstrap = bootstrap;
options.host_name = aws_byte_cursor_from_string(host_name);
options.on_setup = s_http_on_connection_setup;
options.on_shutdown = s_http_on_connection_shutdown;
options.proxy_options = proxy_opts;
options.user_data = binding;
if (tls_opts) {
if (!tls_opts->server_name) {
struct aws_byte_cursor server_name_cursor = aws_byte_cursor_from_string(host_name);
aws_tls_connection_options_set_server_name(tls_opts, allocator, &server_name_cursor);
}
options.tls_options = tls_opts;
}
if (aws_http_client_connect(&options)) {
aws_napi_throw_last_error(env);
goto connect_failed;
}
result = node_external;
goto done;
connect_failed:
create_external_failed:
failed_callbacks:
if (binding) {
AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_setup, napi_tsfn_abort));
AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_shutdown, napi_tsfn_abort));
}
aws_mem_release(allocator, binding);
alloc_failed:
argument_error:
done:
aws_string_destroy(host_name);
return result;
}