django-vue3-admin-web/node_modules/aws-crt/source/http_headers.c
2025-10-20 21:21:14 +08:00

558 lines
19 KiB
C

/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include "http_headers.h"
#include "class_binder.h"
#include <aws/http/request_response.h>
static struct aws_napi_class_info s_headers_class_info;
static aws_napi_method_fn s_headers_constructor;
static aws_napi_property_get_fn s_headers_length_get;
static aws_napi_method_fn s_headers_get;
static aws_napi_method_fn s_headers_get_values;
static aws_napi_method_fn s_headers_get_index;
static aws_napi_method_fn s_headers__iterator;
static aws_napi_method_fn s_headers_add_header;
static aws_napi_method_fn s_headers_set_header;
static aws_napi_method_fn s_headers_remove;
static aws_napi_method_fn s_headers_remove_value;
static aws_napi_method_fn s_headers_clear;
static aws_napi_method_fn s_headers__flatten;
static napi_ref s_iterator_constructor;
static napi_value s_iterator_ctor(napi_env env, napi_callback_info info);
static napi_value s_iterator_next(napi_env env, napi_callback_info info);
napi_status aws_napi_http_headers_bind(napi_env env, napi_value exports) {
static const struct aws_napi_method_info s_headers_constructor_info = {
.name = "HttpHeaders",
.method = s_headers_constructor,
.num_arguments = 0,
.arg_types = {napi_object},
};
static const struct aws_napi_property_info s_headers_properties[] = {
{
.name = "length",
.type = napi_number,
.getter = s_headers_length_get,
.attributes = napi_enumerable,
},
};
static const struct aws_napi_method_info s_headers_methods[] = {
{
.name = "get",
.method = s_headers_get,
.num_arguments = 1,
.arg_types = {napi_string},
},
{
.name = "get_values",
.method = s_headers_get_values,
.num_arguments = 1,
.arg_types = {napi_string},
},
{
.name = "get_index",
.method = s_headers_get_index,
.num_arguments = 1,
.arg_types = {napi_number},
},
{
.symbol = "iterator",
.method = s_headers__iterator,
},
{
.name = "add",
.method = s_headers_add_header,
.num_arguments = 2,
.arg_types = {napi_string, napi_string},
},
{
.name = "set",
.method = s_headers_set_header,
.num_arguments = 2,
.arg_types = {napi_string, napi_string},
},
{
.name = "remove",
.method = s_headers_remove,
.num_arguments = 1,
.arg_types = {napi_string},
},
{
.name = "remove_value",
.method = s_headers_remove_value,
.num_arguments = 2,
.arg_types = {napi_string, napi_string},
},
{
.name = "clear",
.method = s_headers_clear,
.num_arguments = 0,
},
{
.name = "_flatten",
.method = s_headers__flatten,
.num_arguments = 0,
},
};
AWS_NAPI_CALL(
env,
aws_napi_define_class(
env,
exports,
&s_headers_constructor_info,
s_headers_properties,
AWS_ARRAY_SIZE(s_headers_properties),
s_headers_methods,
AWS_ARRAY_SIZE(s_headers_methods),
&s_headers_class_info),
{ return status; });
static const napi_property_descriptor s_iterator_properties[] = {
{
.utf8name = "next",
.method = s_iterator_next,
.attributes = napi_enumerable,
},
};
napi_value iterator_ctor = NULL;
AWS_NAPI_CALL(
env,
napi_define_class(
env,
"Iterator",
NAPI_AUTO_LENGTH,
s_iterator_ctor,
NULL,
AWS_ARRAY_SIZE(s_iterator_properties),
s_iterator_properties,
&iterator_ctor),
{ return status; });
AWS_NAPI_CALL(env, napi_create_reference(env, iterator_ctor, 1, &s_iterator_constructor), { return status; });
return napi_ok;
}
/***********************************************************************************************************************
* Headers
**********************************************************************************************************************/
static void s_napi_http_headers_finalize(napi_env env, void *finalize_data, void *finalize_hint) {
(void)env;
(void)finalize_hint;
aws_http_headers_release(finalize_data);
}
napi_status aws_napi_http_headers_wrap(napi_env env, struct aws_http_headers *headers, napi_value *result) {
aws_http_headers_acquire(headers);
return aws_napi_wrap(env, &s_headers_class_info, headers, s_napi_http_headers_finalize, result);
}
struct aws_http_headers *aws_napi_http_headers_unwrap(napi_env env, napi_value js_object) {
struct aws_http_headers *headers = NULL;
AWS_NAPI_CALL(env, napi_unwrap(env, js_object, (void **)&headers), { return NULL; });
aws_http_headers_acquire(headers);
return headers;
}
static napi_value s_headers_constructor(napi_env env, const struct aws_napi_callback_info *cb_info) {
struct aws_allocator *alloc = aws_napi_get_allocator();
struct aws_http_headers *headers = aws_http_headers_new(alloc);
const struct aws_napi_argument *arg = NULL;
if (aws_napi_method_next_argument(napi_object, cb_info, &arg)) {
napi_value node_headers = arg->node;
bool is_array = false;
if (napi_is_array(env, node_headers, &is_array) || !is_array) {
napi_throw_type_error(env, NULL, "headers must be an array of arrays");
goto cleanup;
}
uint32_t num_headers = 0;
AWS_NAPI_CALL(env, napi_get_array_length(env, node_headers, &num_headers), {
napi_throw_error(env, NULL, "Could not get length of header array");
goto cleanup;
});
struct aws_byte_buf name_buf;
struct aws_byte_buf value_buf;
aws_byte_buf_init(&name_buf, alloc, 256);
aws_byte_buf_init(&value_buf, alloc, 256);
for (uint32_t idx = 0; idx < num_headers; ++idx) {
napi_value node_header = NULL;
AWS_NAPI_CALL(env, napi_get_element(env, node_headers, idx, &node_header), {
napi_throw_error(env, NULL, "Failed to extract headers");
goto header_parse_error;
});
AWS_NAPI_CALL(env, napi_is_array(env, node_header, &is_array), {
napi_throw_error(env, NULL, "Cannot determine if headers are an array");
goto header_parse_error;
});
if (!is_array) {
napi_throw_type_error(env, NULL, "headers must be an array of 2 element arrays");
goto header_parse_error;
}
uint32_t num_parts = 0;
AWS_NAPI_CALL(env, napi_get_array_length(env, node_header, &num_parts), {
napi_throw_error(env, NULL, "Could not get length of header parts");
goto header_parse_error;
});
if (num_parts != 2) {
napi_throw_error(env, NULL, "Could not get length of header parts or length was not 2");
goto header_parse_error;
}
napi_value node_name = NULL;
napi_value node = NULL;
AWS_NAPI_CALL(env, napi_get_element(env, node_header, 0, &node_name), {
napi_throw_error(env, NULL, "Could not extract header name");
goto header_parse_error;
});
AWS_NAPI_CALL(env, napi_get_element(env, node_header, 1, &node), {
napi_throw_error(env, NULL, "Could not extract header value");
goto header_parse_error;
});
/* extract the length of the name and value strings, ensure the buffers can hold them, and
then copy the values out. Should result in buffer re-use most of the time. */
size_t length = 0;
AWS_NAPI_CALL(env, napi_get_value_string_utf8(env, node_name, NULL, 0, &length), {
napi_throw_type_error(env, NULL, "HTTP header was not a string or length could not be extracted");
goto header_parse_error;
});
aws_byte_buf_reserve(&name_buf, length + 1);
AWS_NAPI_CALL(env, napi_get_value_string_utf8(env, node, NULL, 0, &length), {
napi_throw_type_error(env, NULL, "HTTP header was not a string or length could not be extracted");
goto header_parse_error;
});
aws_byte_buf_reserve(&value_buf, length + 1);
AWS_NAPI_CALL(
env,
napi_get_value_string_utf8(env, node_name, (char *)name_buf.buffer, name_buf.capacity, &name_buf.len),
{
napi_throw_error(env, NULL, "HTTP header name could not be extracted");
goto header_parse_error;
});
AWS_NAPI_CALL(
env,
napi_get_value_string_utf8(env, node, (char *)value_buf.buffer, value_buf.capacity, &value_buf.len),
{
napi_throw_error(env, NULL, "HTTP header value could not be extracted");
goto header_parse_error;
});
aws_http_headers_add(headers, aws_byte_cursor_from_buf(&name_buf), aws_byte_cursor_from_buf(&value_buf));
}
aws_byte_buf_clean_up(&name_buf);
aws_byte_buf_clean_up(&value_buf);
goto header_parse_success;
header_parse_error:
aws_byte_buf_clean_up(&name_buf);
aws_byte_buf_clean_up(&value_buf);
goto cleanup;
}
header_parse_success:;
napi_value node_this = cb_info->native_this;
AWS_NAPI_CALL(env, napi_wrap(env, node_this, headers, s_napi_http_headers_finalize, NULL, NULL), {
napi_throw_error(env, NULL, "Failed to wrap HttpHeaders");
goto cleanup;
});
return node_this;
cleanup:
if (headers) {
aws_http_headers_release(headers);
}
return NULL;
}
static napi_value s_headers_length_get(napi_env env, void *native_this) {
struct aws_http_headers *headers = native_this;
napi_value result = NULL;
AWS_NAPI_CALL(env, napi_create_uint32(env, (uint32_t)aws_http_headers_count(headers), &result), {
aws_napi_throw_last_error(env);
});
return result;
}
static napi_value s_headers_create_header_array(napi_env env, const struct aws_http_header *header) {
napi_value node_header = NULL;
AWS_NAPI_ENSURE(env, napi_create_array(env, &node_header));
napi_value node_name = NULL;
napi_value node_value = NULL;
AWS_NAPI_ENSURE(env, napi_create_string_utf8(env, (const char *)header->name.ptr, header->name.len, &node_name));
AWS_NAPI_ENSURE(env, napi_create_string_utf8(env, (const char *)header->value.ptr, header->value.len, &node_value));
AWS_NAPI_ENSURE(env, napi_set_element(env, node_header, 0, node_name));
AWS_NAPI_ENSURE(env, napi_set_element(env, node_header, 1, node_value));
return node_header;
}
static napi_value s_headers_get(napi_env env, const struct aws_napi_callback_info *cb_info) {
(void)env;
AWS_FATAL_ASSERT(cb_info->num_args == 1);
struct aws_http_headers *native_this = cb_info->native_this;
napi_value node_value = NULL;
struct aws_byte_cursor value;
if (aws_http_headers_get(native_this, aws_byte_cursor_from_buf(&cb_info->arguments[0].native.string), &value)) {
if (aws_last_error() != AWS_ERROR_HTTP_HEADER_NOT_FOUND) {
aws_napi_throw_last_error(env);
}
} else {
AWS_NAPI_ENSURE(env, napi_create_string_utf8(env, (const char *)value.ptr, value.len, &node_value));
}
return node_value;
}
static napi_value s_headers_get_values(napi_env env, const struct aws_napi_callback_info *cb_info) {
(void)env;
AWS_FATAL_ASSERT(cb_info->num_args == 1);
struct aws_http_headers *native_this = cb_info->native_this;
const struct aws_byte_cursor key = aws_byte_cursor_from_buf(&cb_info->arguments[0].native.string);
napi_value node_values = NULL;
AWS_NAPI_ENSURE(env, napi_create_array(env, &node_values));
const size_t num_headers = aws_http_headers_count(native_this);
uint32_t array_idx = 0;
for (size_t i = 0; i < num_headers; ++i) {
struct aws_http_header header;
aws_http_headers_get_index(native_this, i, &header);
AWS_ASSUME(header.name.ptr && header.value.ptr);
if (aws_byte_cursor_eq_ignore_case(&header.name, &key)) {
napi_value node_value = NULL;
AWS_NAPI_ENSURE(
env, napi_create_string_utf8(env, (const char *)header.value.ptr, header.value.len, &node_value));
napi_set_element(env, node_values, array_idx++, node_value);
}
}
return node_values;
}
static napi_value s_headers_get_index(napi_env env, const struct aws_napi_callback_info *cb_info) {
AWS_FATAL_ASSERT(cb_info->num_args == 1);
struct aws_http_headers *native_this = cb_info->native_this;
const int64_t index = cb_info->arguments[0].native.number;
if (index < 0 || (size_t)index > SIZE_MAX) {
napi_throw_error(env, NULL, "Header index is out of bounds");
return NULL;
}
struct aws_http_header header;
if (aws_http_headers_get_index(native_this, (size_t)index, &header)) {
aws_napi_throw_last_error(env);
return NULL;
}
return s_headers_create_header_array(env, &header);
}
static napi_value s_headers__iterator(napi_env env, const struct aws_napi_callback_info *cb_info) {
(void)env;
AWS_FATAL_ASSERT(cb_info->num_args == 0);
napi_value iterator_ctor = NULL;
AWS_NAPI_ENSURE(env, napi_get_reference_value(env, s_iterator_constructor, &iterator_ctor));
napi_value node_iterator = NULL;
AWS_NAPI_ENSURE(env, napi_new_instance(env, iterator_ctor, 1, &cb_info->node_this, &node_iterator));
return node_iterator;
}
static napi_value s_headers_add_header(napi_env env, const struct aws_napi_callback_info *cb_info) {
(void)env;
AWS_FATAL_ASSERT(cb_info->num_args == 2);
struct aws_http_headers *native_this = cb_info->native_this;
if (aws_http_headers_add(
native_this,
aws_byte_cursor_from_buf(&cb_info->arguments[0].native.string),
aws_byte_cursor_from_buf(&cb_info->arguments[1].native.string))) {
aws_napi_throw_last_error(env);
}
return NULL;
}
static napi_value s_headers_set_header(napi_env env, const struct aws_napi_callback_info *cb_info) {
AWS_FATAL_ASSERT(cb_info->num_args == 2);
struct aws_http_headers *native_this = cb_info->native_this;
if (aws_http_headers_set(
native_this,
aws_byte_cursor_from_buf(&cb_info->arguments[0].native.string),
aws_byte_cursor_from_buf(&cb_info->arguments[1].native.string))) {
aws_napi_throw_last_error(env);
}
return NULL;
}
static napi_value s_headers_remove(napi_env env, const struct aws_napi_callback_info *cb_info) {
AWS_FATAL_ASSERT(cb_info->num_args == 1);
struct aws_http_headers *native_this = cb_info->native_this;
if (aws_http_headers_erase(native_this, aws_byte_cursor_from_buf(&cb_info->arguments[0].native.string))) {
aws_napi_throw_last_error(env);
}
return NULL;
}
static napi_value s_headers_remove_value(napi_env env, const struct aws_napi_callback_info *cb_info) {
AWS_FATAL_ASSERT(cb_info->num_args == 2);
struct aws_http_headers *native_this = cb_info->native_this;
if (aws_http_headers_erase_value(
native_this,
aws_byte_cursor_from_buf(&cb_info->arguments[0].native.string),
aws_byte_cursor_from_buf(&cb_info->arguments[1].native.string))) {
aws_napi_throw_last_error(env);
}
return NULL;
}
static napi_value s_headers_clear(napi_env env, const struct aws_napi_callback_info *cb_info) {
(void)env;
AWS_FATAL_ASSERT(cb_info->num_args == 0);
struct aws_http_headers *native_this = cb_info->native_this;
aws_http_headers_clear(native_this);
return NULL;
}
static napi_value s_headers__flatten(napi_env env, const struct aws_napi_callback_info *cb_info) {
(void)env;
AWS_FATAL_ASSERT(cb_info->num_args == 0);
struct aws_http_headers *native_this = cb_info->native_this;
napi_value node_values = NULL;
AWS_NAPI_ENSURE(env, napi_create_array(env, &node_values));
const size_t num_headers = aws_http_headers_count(native_this);
uint32_t array_idx = 0;
for (size_t i = 0; i < num_headers; ++i) {
struct aws_http_header header;
aws_http_headers_get_index(native_this, i, &header);
AWS_ASSUME(header.name.ptr && header.value.ptr);
napi_set_element(env, node_values, array_idx++, s_headers_create_header_array(env, &header));
}
return node_values;
}
/***********************************************************************************************************************
* Iterator
**********************************************************************************************************************/
struct headers_iterator {
struct aws_http_headers *headers;
size_t current_index;
};
static void s_iterator_finalize(napi_env env, void *finalize_data, void *finalize_hint) {
(void)env;
struct headers_iterator *iterator = finalize_data;
struct aws_allocator *allocator = finalize_hint;
aws_http_headers_release(iterator->headers);
aws_mem_release(allocator, iterator);
}
static napi_value s_iterator_ctor(napi_env env, napi_callback_info info) {
size_t num_args = 1;
napi_value native_headers = NULL;
napi_value node_this = NULL;
napi_get_cb_info(env, info, &num_args, &native_headers, &node_this, NULL);
struct aws_allocator *allocator = aws_napi_get_allocator();
/* Make and wrap an iterator object */
struct headers_iterator *iterator = aws_mem_calloc(allocator, 1, sizeof(struct headers_iterator));
iterator->headers = aws_napi_http_headers_unwrap(env, native_headers);
iterator->current_index = 0;
AWS_NAPI_ENSURE(env, napi_wrap(env, node_this, iterator, s_iterator_finalize, allocator, NULL));
return node_this;
}
static napi_value s_iterator_next(napi_env env, napi_callback_info info) {
size_t argc = 0;
napi_value node_this = NULL;
AWS_NAPI_ENSURE(env, napi_get_cb_info(env, info, &argc, NULL, &node_this, NULL));
napi_valuetype t;
AWS_NAPI_ENSURE(env, napi_typeof(env, node_this, &t));
struct headers_iterator *iterator = NULL;
AWS_NAPI_ENSURE(env, napi_unwrap(env, node_this, (void **)&iterator));
bool done = false;
napi_value node_value = NULL;
if (iterator->current_index < aws_http_headers_count(iterator->headers)) {
struct aws_http_header header;
aws_http_headers_get_index(iterator->headers, iterator->current_index, &header);
node_value = s_headers_create_header_array(env, &header);
++iterator->current_index;
} else {
done = true;
AWS_NAPI_ENSURE(env, napi_get_undefined(env, &node_value));
}
napi_value node_done = NULL;
AWS_NAPI_ENSURE(env, napi_get_boolean(env, done, &node_done));
napi_value result = NULL;
AWS_NAPI_ENSURE(env, napi_create_object(env, &result));
AWS_NAPI_ENSURE(env, napi_set_named_property(env, result, "done", node_done));
AWS_NAPI_ENSURE(env, napi_set_named_property(env, result, "value", node_value));
return result;
}