in source/http_stream.c [227:345]
napi_value aws_napi_http_stream_new(napi_env env, napi_callback_info info) {
struct aws_allocator *allocator = aws_napi_get_allocator();
napi_value result = NULL;
napi_value node_args[5];
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_stream_new needs exactly 5 arguments");
return NULL;
}
struct http_connection_binding *connection_binding = NULL;
napi_value node_binding = *arg++;
AWS_NAPI_CALL(env, napi_get_value_external(env, node_binding, (void **)&connection_binding), {
napi_throw_error(env, NULL, "Unable to extract connection from external");
return NULL;
});
napi_value node_request = *arg++;
struct aws_http_message *request = aws_napi_http_message_unwrap(env, node_request);
/* adding a refcount for the request, which will be released as the stream object from JS land get destroyed */
aws_http_message_acquire(request);
napi_value node_on_complete = *arg++;
napi_value node_on_response = *arg++;
napi_value node_on_body = *arg++;
struct http_stream_binding *binding = aws_mem_calloc(allocator, 1, sizeof(struct http_stream_binding));
if (!binding) {
aws_napi_throw_last_error(env);
goto failed_binding_alloc;
}
binding->allocator = allocator;
binding->request = request;
aws_atomic_init_int(&binding->pending_length, 0);
AWS_NAPI_CALL(
env,
aws_napi_create_threadsafe_function(
env, node_on_complete, "aws_http_stream_on_complete", s_on_complete_call, binding, &binding->on_complete),
{
napi_throw_error(env, NULL, "on_complete must be a callback");
goto failed_callbacks;
});
if (!aws_napi_is_null_or_undefined(env, node_on_response)) {
AWS_NAPI_CALL(
env,
aws_napi_create_threadsafe_function(
env,
node_on_response,
"aws_http_stream_on_response",
s_on_response_call,
binding,
&binding->on_response),
{
napi_throw_error(env, NULL, "Unable to bind on_response callback");
goto failed_callbacks;
});
}
if (!aws_napi_is_null_or_undefined(env, node_on_body)) {
AWS_NAPI_CALL(
env,
aws_napi_create_threadsafe_function(
env, node_on_body, "aws_http_stream_on_body", s_on_body_call, binding, &binding->on_body),
{
napi_throw_error(env, NULL, "Unable to bind on_body callback");
goto failed_callbacks;
});
}
struct aws_http_make_request_options request_options = {
.self_size = sizeof(struct aws_http_make_request_options),
.request = request,
.user_data = binding,
.on_response_headers = s_on_response_headers,
.on_response_header_block_done = s_on_response_header_block_done,
.on_response_body = s_on_response_body,
.on_complete = s_on_complete,
};
/* becomes the native_handle for the JS object */
AWS_NAPI_CALL(env, napi_create_external(env, binding, s_http_stream_binding_finalize, NULL, &result), {
napi_throw_error(env, NULL, "Unable to create stream external");
goto failed_external;
});
struct aws_http_connection *connection = aws_napi_get_http_connection(connection_binding);
binding->stream = aws_http_connection_make_request(connection, &request_options);
if (!binding->stream) {
napi_throw_error(env, NULL, "Unable to create native aws_http_stream");
result = NULL;
goto failed_request;
}
goto done;
failed_request:
failed_external:
failed_callbacks:
if (binding) {
AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_complete, napi_tsfn_abort));
AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_response, napi_tsfn_abort));
AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_body, napi_tsfn_abort));
}
aws_mem_release(allocator, binding);
failed_binding_alloc:
done:
return result;
}