1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228 |
- /**
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0.
- */
- #include <aws/common/array_list.h>
- #include <aws/common/mutex.h>
- #include <aws/common/string.h>
- #include <aws/http/private/connection_impl.h>
- #include <aws/http/private/request_response_impl.h>
- #include <aws/http/private/strutil.h>
- #include <aws/http/server.h>
- #include <aws/http/status_code.h>
- #include <aws/io/logging.h>
- #include <aws/io/stream.h>
- #ifdef _MSC_VER
- # pragma warning(disable : 4204) /* non-constant aggregate initializer */
- #endif
- enum {
- /* Initial capacity for the aws_http_message.headers array_list. */
- AWS_HTTP_REQUEST_NUM_RESERVED_HEADERS = 16,
- };
- bool aws_http_header_name_eq(struct aws_byte_cursor name_a, struct aws_byte_cursor name_b) {
- return aws_byte_cursor_eq_ignore_case(&name_a, &name_b);
- }
- /**
- * -- Data Structure Notes --
- * Headers are stored in a linear array, rather than a hash-table of arrays.
- * The linear array was simpler to implement and may be faster due to having fewer allocations.
- * The API has been designed so we can swap out the implementation later if desired.
- *
- * -- String Storage Notes --
- * We use a single allocation to hold the name and value of each aws_http_header.
- * We could optimize storage by using something like a string pool. If we do this, be sure to maintain
- * the address of existing strings when adding new strings (a dynamic aws_byte_buf would not suffice).
- */
- struct aws_http_headers {
- struct aws_allocator *alloc;
- struct aws_array_list array_list; /* Contains aws_http_header */
- struct aws_atomic_var refcount;
- };
- struct aws_http_headers *aws_http_headers_new(struct aws_allocator *allocator) {
- AWS_PRECONDITION(allocator);
- struct aws_http_headers *headers = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_headers));
- if (!headers) {
- goto alloc_failed;
- }
- headers->alloc = allocator;
- aws_atomic_init_int(&headers->refcount, 1);
- if (aws_array_list_init_dynamic(
- &headers->array_list, allocator, AWS_HTTP_REQUEST_NUM_RESERVED_HEADERS, sizeof(struct aws_http_header))) {
- goto array_list_failed;
- }
- return headers;
- array_list_failed:
- aws_mem_release(headers->alloc, headers);
- alloc_failed:
- return NULL;
- }
- void aws_http_headers_release(struct aws_http_headers *headers) {
- AWS_PRECONDITION(!headers || headers->alloc);
- if (!headers) {
- return;
- }
- size_t prev_refcount = aws_atomic_fetch_sub(&headers->refcount, 1);
- if (prev_refcount == 1) {
- aws_http_headers_clear(headers);
- aws_array_list_clean_up(&headers->array_list);
- aws_mem_release(headers->alloc, headers);
- } else {
- AWS_ASSERT(prev_refcount != 0);
- }
- }
- void aws_http_headers_acquire(struct aws_http_headers *headers) {
- AWS_PRECONDITION(headers);
- aws_atomic_fetch_add(&headers->refcount, 1);
- }
- static int s_http_headers_add_header_impl(
- struct aws_http_headers *headers,
- const struct aws_http_header *header_orig,
- bool front) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(header_orig);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&header_orig->name) && aws_byte_cursor_is_valid(&header_orig->value));
- struct aws_http_header header_copy = *header_orig;
- if (header_copy.name.len == 0) {
- return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_NAME);
- }
- /* Whitespace around header values is ignored (RFC-7230 - Section 3.2).
- * Trim it off here, so anyone querying this value has an easier time. */
- header_copy.value = aws_strutil_trim_http_whitespace(header_copy.value);
- size_t total_len;
- if (aws_add_size_checked(header_copy.name.len, header_copy.value.len, &total_len)) {
- return AWS_OP_ERR;
- }
- /* Store our own copy of the strings.
- * We put the name and value into the same allocation. */
- uint8_t *strmem = aws_mem_acquire(headers->alloc, total_len);
- struct aws_byte_buf strbuf = aws_byte_buf_from_empty_array(strmem, total_len);
- aws_byte_buf_append_and_update(&strbuf, &header_copy.name);
- aws_byte_buf_append_and_update(&strbuf, &header_copy.value);
- if (front) {
- if (aws_array_list_push_front(&headers->array_list, &header_copy)) {
- goto error;
- }
- } else {
- if (aws_array_list_push_back(&headers->array_list, &header_copy)) {
- goto error;
- }
- }
- return AWS_OP_SUCCESS;
- error:
- aws_mem_release(headers->alloc, strmem);
- return AWS_OP_ERR;
- }
- int aws_http_headers_add_header(struct aws_http_headers *headers, const struct aws_http_header *header) {
- /* Add pseudo headers to the front and not checking any violation until we send the header to the wire */
- bool pseudo = aws_strutil_is_http_pseudo_header_name(header->name);
- bool front = false;
- if (pseudo && aws_http_headers_count(headers)) {
- struct aws_http_header last_header;
- /* TODO: instead if checking the last header, maybe we can add the pseudo headers to the end of the existing
- * pseudo headers, which needs to insert to the middle of the array list. */
- AWS_ZERO_STRUCT(last_header);
- aws_http_headers_get_index(headers, aws_http_headers_count(headers) - 1, &last_header);
- front = !aws_strutil_is_http_pseudo_header_name(last_header.name);
- }
- return s_http_headers_add_header_impl(headers, header, front);
- }
- int aws_http_headers_add(struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value) {
- struct aws_http_header header = {.name = name, .value = value};
- return aws_http_headers_add_header(headers, &header);
- }
- void aws_http_headers_clear(struct aws_http_headers *headers) {
- AWS_PRECONDITION(headers);
- struct aws_http_header *header = NULL;
- const size_t count = aws_http_headers_count(headers);
- for (size_t i = 0; i < count; ++i) {
- aws_array_list_get_at_ptr(&headers->array_list, (void **)&header, i);
- AWS_ASSUME(header);
- /* Storage for name & value is in the same allocation */
- aws_mem_release(headers->alloc, header->name.ptr);
- }
- aws_array_list_clear(&headers->array_list);
- }
- /* Does not check index */
- static void s_http_headers_erase_index(struct aws_http_headers *headers, size_t index) {
- struct aws_http_header *header = NULL;
- aws_array_list_get_at_ptr(&headers->array_list, (void **)&header, index);
- AWS_ASSUME(header);
- /* Storage for name & value is in the same allocation */
- aws_mem_release(headers->alloc, header->name.ptr);
- aws_array_list_erase(&headers->array_list, index);
- }
- int aws_http_headers_erase_index(struct aws_http_headers *headers, size_t index) {
- AWS_PRECONDITION(headers);
- if (index >= aws_http_headers_count(headers)) {
- return aws_raise_error(AWS_ERROR_INVALID_INDEX);
- }
- s_http_headers_erase_index(headers, index);
- return AWS_OP_SUCCESS;
- }
- /* Erase entries with name, stop at end_index */
- static int s_http_headers_erase(
- struct aws_http_headers *headers,
- struct aws_byte_cursor name,
- size_t start_index,
- size_t end_index) {
- bool erased_any = false;
- struct aws_http_header *header = NULL;
- /* Iterating in reverse is simpler */
- for (size_t n = end_index; n > start_index; --n) {
- const size_t i = n - 1;
- aws_array_list_get_at_ptr(&headers->array_list, (void **)&header, i);
- AWS_ASSUME(header);
- if (aws_http_header_name_eq(header->name, name)) {
- s_http_headers_erase_index(headers, i);
- erased_any = true;
- }
- }
- if (!erased_any) {
- return aws_raise_error(AWS_ERROR_HTTP_HEADER_NOT_FOUND);
- }
- return AWS_OP_SUCCESS;
- }
- int aws_http_headers_erase(struct aws_http_headers *headers, struct aws_byte_cursor name) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&name));
- return s_http_headers_erase(headers, name, 0, aws_http_headers_count(headers));
- }
- int aws_http_headers_erase_value(
- struct aws_http_headers *headers,
- struct aws_byte_cursor name,
- struct aws_byte_cursor value) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&name) && aws_byte_cursor_is_valid(&value));
- struct aws_http_header *header = NULL;
- const size_t count = aws_http_headers_count(headers);
- for (size_t i = 0; i < count; ++i) {
- aws_array_list_get_at_ptr(&headers->array_list, (void **)&header, i);
- AWS_ASSUME(header);
- if (aws_http_header_name_eq(header->name, name) && aws_byte_cursor_eq(&header->value, &value)) {
- s_http_headers_erase_index(headers, i);
- return AWS_OP_SUCCESS;
- }
- }
- return aws_raise_error(AWS_ERROR_HTTP_HEADER_NOT_FOUND);
- }
- int aws_http_headers_add_array(struct aws_http_headers *headers, const struct aws_http_header *array, size_t count) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(AWS_MEM_IS_READABLE(array, count));
- const size_t orig_count = aws_http_headers_count(headers);
- for (size_t i = 0; i < count; ++i) {
- if (aws_http_headers_add_header(headers, &array[i])) {
- goto error;
- }
- }
- return AWS_OP_SUCCESS;
- error:
- /* Erase headers from the end until we're back to our previous state */
- for (size_t new_count = aws_http_headers_count(headers); new_count > orig_count; --new_count) {
- s_http_headers_erase_index(headers, new_count - 1);
- }
- return AWS_OP_ERR;
- }
- int aws_http_headers_set(struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&name) && aws_byte_cursor_is_valid(&value));
- const size_t prev_count = aws_http_headers_count(headers);
- bool pseudo = aws_strutil_is_http_pseudo_header_name(name);
- const size_t start = pseudo ? 1 : 0;
- struct aws_http_header header = {.name = name, .value = value};
- if (s_http_headers_add_header_impl(headers, &header, pseudo)) {
- return AWS_OP_ERR;
- }
- /* Erase pre-existing headers AFTER add, in case name or value was referencing their memory. */
- s_http_headers_erase(headers, name, start, prev_count);
- return AWS_OP_SUCCESS;
- }
- size_t aws_http_headers_count(const struct aws_http_headers *headers) {
- AWS_PRECONDITION(headers);
- return aws_array_list_length(&headers->array_list);
- }
- int aws_http_headers_get_index(
- const struct aws_http_headers *headers,
- size_t index,
- struct aws_http_header *out_header) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(out_header);
- return aws_array_list_get_at(&headers->array_list, out_header, index);
- }
- /* RFC-9110 - 5.3
- * A recipient MAY combine multiple field lines within a field section that
- * have the same field name into one field line, without changing the semantics
- * of the message, by appending each subsequent field line value to the initial
- * field line value in order, separated by a comma (",") and optional whitespace
- * (OWS, defined in Section 5.6.3). For consistency, use comma SP. */
- AWS_HTTP_API
- struct aws_string *aws_http_headers_get_all(const struct aws_http_headers *headers, struct aws_byte_cursor name) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&name));
- struct aws_string *value_str = NULL;
- const struct aws_byte_cursor separator = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(", ");
- struct aws_byte_buf value_builder;
- aws_byte_buf_init(&value_builder, headers->alloc, 0);
- bool found = false;
- struct aws_http_header *header = NULL;
- const size_t count = aws_http_headers_count(headers);
- for (size_t i = 0; i < count; ++i) {
- aws_array_list_get_at_ptr(&headers->array_list, (void **)&header, i);
- if (aws_http_header_name_eq(name, header->name)) {
- if (!found) {
- found = true;
- } else {
- aws_byte_buf_append_dynamic(&value_builder, &separator);
- }
- aws_byte_buf_append_dynamic(&value_builder, &header->value);
- }
- }
- if (found) {
- value_str = aws_string_new_from_buf(headers->alloc, &value_builder);
- } else {
- aws_raise_error(AWS_ERROR_HTTP_HEADER_NOT_FOUND);
- }
- aws_byte_buf_clean_up(&value_builder);
- return value_str;
- }
- int aws_http_headers_get(
- const struct aws_http_headers *headers,
- struct aws_byte_cursor name,
- struct aws_byte_cursor *out_value) {
- AWS_PRECONDITION(headers);
- AWS_PRECONDITION(out_value);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&name));
- struct aws_http_header *header = NULL;
- const size_t count = aws_http_headers_count(headers);
- for (size_t i = 0; i < count; ++i) {
- aws_array_list_get_at_ptr(&headers->array_list, (void **)&header, i);
- AWS_ASSUME(header);
- if (aws_http_header_name_eq(header->name, name)) {
- *out_value = header->value;
- return AWS_OP_SUCCESS;
- }
- }
- return aws_raise_error(AWS_ERROR_HTTP_HEADER_NOT_FOUND);
- }
- bool aws_http_headers_has(const struct aws_http_headers *headers, struct aws_byte_cursor name) {
- struct aws_byte_cursor out_value;
- if (aws_http_headers_get(headers, name, &out_value)) {
- return false;
- }
- return true;
- }
- int aws_http2_headers_get_request_method(
- const struct aws_http_headers *h2_headers,
- struct aws_byte_cursor *out_method) {
- return aws_http_headers_get(h2_headers, aws_http_header_method, out_method);
- }
- int aws_http2_headers_get_request_scheme(
- const struct aws_http_headers *h2_headers,
- struct aws_byte_cursor *out_scheme) {
- return aws_http_headers_get(h2_headers, aws_http_header_scheme, out_scheme);
- }
- int aws_http2_headers_get_request_authority(
- const struct aws_http_headers *h2_headers,
- struct aws_byte_cursor *out_authority) {
- return aws_http_headers_get(h2_headers, aws_http_header_authority, out_authority);
- }
- int aws_http2_headers_get_request_path(const struct aws_http_headers *h2_headers, struct aws_byte_cursor *out_path) {
- return aws_http_headers_get(h2_headers, aws_http_header_path, out_path);
- }
- int aws_http2_headers_get_response_status(const struct aws_http_headers *h2_headers, int *out_status_code) {
- struct aws_byte_cursor status_code_cur;
- int return_code = aws_http_headers_get(h2_headers, aws_http_header_status, &status_code_cur);
- if (return_code == AWS_OP_SUCCESS) {
- uint64_t code_val_u64;
- if (aws_byte_cursor_utf8_parse_u64(status_code_cur, &code_val_u64)) {
- return AWS_OP_ERR;
- }
- *out_status_code = (int)code_val_u64;
- }
- return return_code;
- }
- int aws_http2_headers_set_request_method(struct aws_http_headers *h2_headers, struct aws_byte_cursor method) {
- return aws_http_headers_set(h2_headers, aws_http_header_method, method);
- }
- int aws_http2_headers_set_request_scheme(struct aws_http_headers *h2_headers, struct aws_byte_cursor scheme) {
- return aws_http_headers_set(h2_headers, aws_http_header_scheme, scheme);
- }
- int aws_http2_headers_set_request_authority(struct aws_http_headers *h2_headers, struct aws_byte_cursor authority) {
- return aws_http_headers_set(h2_headers, aws_http_header_authority, authority);
- }
- int aws_http2_headers_set_request_path(struct aws_http_headers *h2_headers, struct aws_byte_cursor path) {
- return aws_http_headers_set(h2_headers, aws_http_header_path, path);
- }
- int aws_http2_headers_set_response_status(struct aws_http_headers *h2_headers, int status_code) {
- /* Status code must fit in 3 digits */
- if (status_code < 0 || status_code > 999) {
- return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- }
- char status_code_str[4] = "000";
- snprintf(status_code_str, sizeof(status_code_str), "%03d", status_code);
- struct aws_byte_cursor status_code_cur = aws_byte_cursor_from_c_str(status_code_str);
- return aws_http_headers_set(h2_headers, aws_http_header_status, status_code_cur);
- }
- struct aws_http_message {
- struct aws_allocator *allocator;
- struct aws_http_headers *headers;
- struct aws_input_stream *body_stream;
- struct aws_atomic_var refcount;
- enum aws_http_version http_version;
- /* Data specific to the request or response subclasses */
- union {
- struct aws_http_message_request_data {
- struct aws_string *method;
- struct aws_string *path;
- } request;
- struct aws_http_message_response_data {
- int status;
- } response;
- } subclass_data;
- struct aws_http_message_request_data *request_data;
- struct aws_http_message_response_data *response_data;
- };
- static int s_set_string_from_cursor(
- struct aws_string **dst,
- struct aws_byte_cursor cursor,
- struct aws_allocator *alloc) {
- AWS_PRECONDITION(dst);
- /* If the cursor is empty, set dst to NULL */
- struct aws_string *new_str;
- if (cursor.len) {
- new_str = aws_string_new_from_cursor(alloc, &cursor);
- if (!new_str) {
- return AWS_OP_ERR;
- }
- } else {
- new_str = NULL;
- }
- /* Replace existing value */
- aws_string_destroy(*dst);
- *dst = new_str;
- return AWS_OP_SUCCESS;
- }
- static struct aws_http_message *s_message_new_common(
- struct aws_allocator *allocator,
- struct aws_http_headers *existing_headers) {
- /* allocation cannot fail */
- struct aws_http_message *message = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_message));
- message->allocator = allocator;
- aws_atomic_init_int(&message->refcount, 1);
- if (existing_headers) {
- message->headers = existing_headers;
- aws_http_headers_acquire(message->headers);
- } else {
- message->headers = aws_http_headers_new(allocator);
- if (!message->headers) {
- goto error;
- }
- }
- return message;
- error:
- aws_http_message_destroy(message);
- return NULL;
- }
- static struct aws_http_message *s_message_new_request_common(
- struct aws_allocator *allocator,
- struct aws_http_headers *existing_headers,
- enum aws_http_version version) {
- struct aws_http_message *message = s_message_new_common(allocator, existing_headers);
- if (message) {
- message->request_data = &message->subclass_data.request;
- message->http_version = version;
- }
- return message;
- }
- struct aws_http_message *aws_http_message_new_request_with_headers(
- struct aws_allocator *allocator,
- struct aws_http_headers *existing_headers) {
- AWS_PRECONDITION(allocator);
- AWS_PRECONDITION(existing_headers);
- return s_message_new_request_common(allocator, existing_headers, AWS_HTTP_VERSION_1_1);
- }
- struct aws_http_message *aws_http_message_new_request(struct aws_allocator *allocator) {
- AWS_PRECONDITION(allocator);
- return s_message_new_request_common(allocator, NULL, AWS_HTTP_VERSION_1_1);
- }
- struct aws_http_message *aws_http2_message_new_request(struct aws_allocator *allocator) {
- AWS_PRECONDITION(allocator);
- return s_message_new_request_common(allocator, NULL, AWS_HTTP_VERSION_2);
- }
- static struct aws_http_message *s_http_message_new_response_common(
- struct aws_allocator *allocator,
- enum aws_http_version version) {
- AWS_PRECONDITION(allocator);
- struct aws_http_message *message = s_message_new_common(allocator, NULL);
- if (message) {
- message->response_data = &message->subclass_data.response;
- message->response_data->status = AWS_HTTP_STATUS_CODE_UNKNOWN;
- message->http_version = version;
- }
- return message;
- }
- struct aws_http_message *aws_http_message_new_response(struct aws_allocator *allocator) {
- AWS_PRECONDITION(allocator);
- return s_http_message_new_response_common(allocator, AWS_HTTP_VERSION_1_1);
- }
- struct aws_http_message *aws_http2_message_new_response(struct aws_allocator *allocator) {
- AWS_PRECONDITION(allocator);
- return s_http_message_new_response_common(allocator, AWS_HTTP_VERSION_2);
- }
- void aws_http_message_destroy(struct aws_http_message *message) {
- aws_http_message_release(message);
- }
- struct aws_http_message *aws_http_message_release(struct aws_http_message *message) {
- /* Note that release() may also be used by new() functions to clean up if something goes wrong */
- AWS_PRECONDITION(!message || message->allocator);
- if (!message) {
- return NULL;
- }
- size_t prev_refcount = aws_atomic_fetch_sub(&message->refcount, 1);
- if (prev_refcount == 1) {
- if (message->request_data) {
- aws_string_destroy(message->request_data->method);
- aws_string_destroy(message->request_data->path);
- }
- aws_http_headers_release(message->headers);
- aws_input_stream_release(message->body_stream);
- aws_mem_release(message->allocator, message);
- } else {
- AWS_ASSERT(prev_refcount != 0);
- }
- return NULL;
- }
- struct aws_http_message *aws_http_message_acquire(struct aws_http_message *message) {
- if (message != NULL) {
- aws_atomic_fetch_add(&message->refcount, 1);
- }
- return message;
- }
- bool aws_http_message_is_request(const struct aws_http_message *message) {
- AWS_PRECONDITION(message);
- return message->request_data;
- }
- bool aws_http_message_is_response(const struct aws_http_message *message) {
- AWS_PRECONDITION(message);
- return message->response_data;
- }
- enum aws_http_version aws_http_message_get_protocol_version(const struct aws_http_message *message) {
- AWS_PRECONDITION(message);
- return message->http_version;
- }
- int aws_http_message_set_request_method(struct aws_http_message *request_message, struct aws_byte_cursor method) {
- AWS_PRECONDITION(request_message);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&method));
- AWS_PRECONDITION(request_message->request_data);
- if (request_message->request_data) {
- switch (request_message->http_version) {
- case AWS_HTTP_VERSION_1_1:
- return s_set_string_from_cursor(
- &request_message->request_data->method, method, request_message->allocator);
- case AWS_HTTP_VERSION_2:
- return aws_http2_headers_set_request_method(request_message->headers, method);
- default:
- return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
- }
- }
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- int aws_http_message_get_request_method(
- const struct aws_http_message *request_message,
- struct aws_byte_cursor *out_method) {
- AWS_PRECONDITION(request_message);
- AWS_PRECONDITION(out_method);
- AWS_PRECONDITION(request_message->request_data);
- int error = AWS_ERROR_HTTP_DATA_NOT_AVAILABLE;
- if (request_message->request_data) {
- switch (request_message->http_version) {
- case AWS_HTTP_VERSION_1_1:
- if (request_message->request_data->method) {
- *out_method = aws_byte_cursor_from_string(request_message->request_data->method);
- return AWS_OP_SUCCESS;
- }
- break;
- case AWS_HTTP_VERSION_2:
- return aws_http2_headers_get_request_method(request_message->headers, out_method);
- default:
- error = AWS_ERROR_UNIMPLEMENTED;
- }
- }
- AWS_ZERO_STRUCT(*out_method);
- return aws_raise_error(error);
- }
- int aws_http_message_set_request_path(struct aws_http_message *request_message, struct aws_byte_cursor path) {
- AWS_PRECONDITION(request_message);
- AWS_PRECONDITION(aws_byte_cursor_is_valid(&path));
- AWS_PRECONDITION(request_message->request_data);
- if (request_message->request_data) {
- switch (request_message->http_version) {
- case AWS_HTTP_VERSION_1_1:
- return s_set_string_from_cursor(&request_message->request_data->path, path, request_message->allocator);
- case AWS_HTTP_VERSION_2:
- return aws_http2_headers_set_request_path(request_message->headers, path);
- default:
- return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
- }
- }
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- int aws_http_message_get_request_path(
- const struct aws_http_message *request_message,
- struct aws_byte_cursor *out_path) {
- AWS_PRECONDITION(request_message);
- AWS_PRECONDITION(out_path);
- AWS_PRECONDITION(request_message->request_data);
- if (request_message->request_data) {
- switch (request_message->http_version) {
- case AWS_HTTP_VERSION_1_1:
- if (request_message->request_data->path) {
- *out_path = aws_byte_cursor_from_string(request_message->request_data->path);
- return AWS_OP_SUCCESS;
- }
- break;
- case AWS_HTTP_VERSION_2:
- return aws_http2_headers_get_request_path(request_message->headers, out_path);
- default:
- return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
- }
- }
- AWS_ZERO_STRUCT(*out_path);
- return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
- }
- int aws_http_message_get_response_status(const struct aws_http_message *response_message, int *out_status_code) {
- AWS_PRECONDITION(response_message);
- AWS_PRECONDITION(out_status_code);
- AWS_PRECONDITION(response_message->response_data);
- *out_status_code = AWS_HTTP_STATUS_CODE_UNKNOWN;
- if (response_message->response_data) {
- switch (response_message->http_version) {
- case AWS_HTTP_VERSION_1_1:
- if (response_message->response_data->status != AWS_HTTP_STATUS_CODE_UNKNOWN) {
- *out_status_code = response_message->response_data->status;
- return AWS_OP_SUCCESS;
- }
- break;
- case AWS_HTTP_VERSION_2:
- return aws_http2_headers_get_response_status(response_message->headers, out_status_code);
- default:
- return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
- }
- }
- return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
- }
- int aws_http_message_set_response_status(struct aws_http_message *response_message, int status_code) {
- AWS_PRECONDITION(response_message);
- AWS_PRECONDITION(response_message->response_data);
- if (response_message->response_data) {
- /* Status code must be printable with exactly 3 digits */
- if (status_code >= 0 && status_code <= 999) {
- switch (response_message->http_version) {
- case AWS_HTTP_VERSION_1_1:
- response_message->response_data->status = status_code;
- return AWS_OP_SUCCESS;
- case AWS_HTTP_VERSION_2:
- return aws_http2_headers_set_response_status(response_message->headers, status_code);
- default:
- return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
- }
- }
- return aws_raise_error(AWS_ERROR_HTTP_INVALID_STATUS_CODE);
- }
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- void aws_http_message_set_body_stream(struct aws_http_message *message, struct aws_input_stream *body_stream) {
- AWS_PRECONDITION(message);
- /* release previous stream, if any */
- aws_input_stream_release(message->body_stream);
- message->body_stream = body_stream;
- if (message->body_stream) {
- aws_input_stream_acquire(message->body_stream);
- }
- }
- int aws_http1_stream_write_chunk(struct aws_http_stream *http1_stream, const struct aws_http1_chunk_options *options) {
- AWS_PRECONDITION(http1_stream);
- AWS_PRECONDITION(http1_stream->vtable);
- AWS_PRECONDITION(options);
- if (!http1_stream->vtable->http1_write_chunk) {
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_STREAM,
- "id=%p: HTTP/1 stream only function invoked on other stream, ignoring call.",
- (void *)http1_stream);
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- return http1_stream->vtable->http1_write_chunk(http1_stream, options);
- }
- int aws_http2_stream_write_data(
- struct aws_http_stream *http2_stream,
- const struct aws_http2_stream_write_data_options *options) {
- AWS_PRECONDITION(http2_stream);
- AWS_PRECONDITION(http2_stream->vtable);
- AWS_PRECONDITION(http2_stream->vtable->http2_write_data);
- AWS_PRECONDITION(options);
- return http2_stream->vtable->http2_write_data(http2_stream, options);
- }
- int aws_http1_stream_add_chunked_trailer(
- struct aws_http_stream *http1_stream,
- const struct aws_http_headers *trailing_headers) {
- AWS_PRECONDITION(http1_stream);
- AWS_PRECONDITION(http1_stream->vtable);
- AWS_PRECONDITION(trailing_headers);
- if (!http1_stream->vtable->http1_add_trailer) {
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_STREAM,
- "id=%p: HTTP/1 stream only function invoked on other stream, ignoring call.",
- (void *)http1_stream);
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- return http1_stream->vtable->http1_add_trailer(http1_stream, trailing_headers);
- }
- struct aws_input_stream *aws_http_message_get_body_stream(const struct aws_http_message *message) {
- AWS_PRECONDITION(message);
- return message->body_stream;
- }
- struct aws_http_headers *aws_http_message_get_headers(const struct aws_http_message *message) {
- AWS_PRECONDITION(message);
- return message->headers;
- }
- const struct aws_http_headers *aws_http_message_get_const_headers(const struct aws_http_message *message) {
- AWS_PRECONDITION(message);
- return message->headers;
- }
- int aws_http_message_add_header(struct aws_http_message *message, struct aws_http_header header) {
- return aws_http_headers_add(message->headers, header.name, header.value);
- }
- int aws_http_message_add_header_array(
- struct aws_http_message *message,
- const struct aws_http_header *headers,
- size_t num_headers) {
- return aws_http_headers_add_array(message->headers, headers, num_headers);
- }
- int aws_http_message_erase_header(struct aws_http_message *message, size_t index) {
- return aws_http_headers_erase_index(message->headers, index);
- }
- size_t aws_http_message_get_header_count(const struct aws_http_message *message) {
- return aws_http_headers_count(message->headers);
- }
- int aws_http_message_get_header(
- const struct aws_http_message *message,
- struct aws_http_header *out_header,
- size_t index) {
- return aws_http_headers_get_index(message->headers, index, out_header);
- }
- struct aws_http_stream *aws_http_connection_make_request(
- struct aws_http_connection *client_connection,
- const struct aws_http_make_request_options *options) {
- AWS_PRECONDITION(client_connection);
- AWS_PRECONDITION(aws_http_connection_is_client(client_connection));
- AWS_PRECONDITION(options);
- if (options->self_size == 0 || !options->request || !aws_http_message_is_request(options->request)) {
- AWS_LOGF_ERROR(
- AWS_LS_HTTP_CONNECTION,
- "id=%p: Cannot create client request, options are invalid.",
- (void *)client_connection);
- aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- return NULL;
- }
- /* Connection owns stream, and must outlive stream */
- aws_http_connection_acquire(client_connection);
- struct aws_http_stream *stream = client_connection->vtable->make_request(client_connection, options);
- if (!stream) {
- aws_http_connection_release(client_connection);
- return NULL;
- }
- return stream;
- }
- struct aws_http_message *aws_http2_message_new_from_http1(
- struct aws_allocator *alloc,
- const struct aws_http_message *http1_msg) {
- struct aws_http_headers *old_headers = aws_http_message_get_headers(http1_msg);
- struct aws_http_header header_iter;
- struct aws_byte_buf lower_name_buf;
- AWS_ZERO_STRUCT(lower_name_buf);
- struct aws_http_message *message = aws_http_message_is_request(http1_msg) ? aws_http2_message_new_request(alloc)
- : aws_http2_message_new_response(alloc);
- if (!message) {
- return NULL;
- }
- struct aws_http_headers *copied_headers = message->headers;
- AWS_LOGF_TRACE(AWS_LS_HTTP_GENERAL, "Creating HTTP/2 message from HTTP/1 message id: %p", (void *)http1_msg);
- /* Set pseudo headers from HTTP/1.1 message */
- if (aws_http_message_is_request(http1_msg)) {
- struct aws_byte_cursor method;
- if (aws_http_message_get_request_method(http1_msg, &method)) {
- AWS_LOGF_ERROR(
- AWS_LS_HTTP_GENERAL,
- "Failed to create HTTP/2 message from HTTP/1 message, ip: %p, due to no method found.",
- (void *)http1_msg);
- /* error will happen when the request is invalid */
- aws_raise_error(AWS_ERROR_HTTP_INVALID_METHOD);
- goto error;
- }
- /* Use add instead of set method to avoid push front to the array list */
- if (aws_http_headers_add(copied_headers, aws_http_header_method, method)) {
- goto error;
- }
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Added header to new HTTP/2 header - \"%.*s\": \"%.*s\" ",
- (int)aws_http_header_method.len,
- aws_http_header_method.ptr,
- (int)method.len,
- method.ptr);
- /**
- * we set a default value, "https", for now.
- * TODO: as we support prior knowledge, we may also want to support http?
- */
- struct aws_byte_cursor scheme_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("https");
- if (aws_http_headers_add(copied_headers, aws_http_header_scheme, scheme_cursor)) {
- goto error;
- }
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Added header to new HTTP/2 header - \"%.*s\": \"%.*s\" ",
- (int)aws_http_header_scheme.len,
- aws_http_header_scheme.ptr,
- (int)scheme_cursor.len,
- scheme_cursor.ptr);
- /**
- * An intermediary that forwards a request over HTTP/2 MUST construct an ":authority" pseudo-header field using
- * the authority information from the control data of the original request. (RFC=9113 8.3.1)
- */
- struct aws_byte_cursor host_value;
- AWS_ZERO_STRUCT(host_value);
- if (aws_http_headers_get(http1_msg->headers, aws_byte_cursor_from_c_str("host"), &host_value) ==
- AWS_OP_SUCCESS) {
- if (aws_http_headers_add(copied_headers, aws_http_header_authority, host_value)) {
- goto error;
- }
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Added header to new HTTP/2 header - \"%.*s\": \"%.*s\" ",
- (int)aws_http_header_authority.len,
- aws_http_header_authority.ptr,
- (int)host_value.len,
- host_value.ptr);
- }
- /* TODO: If the host headers is missing, the target URI could be the other source of the authority information
- */
- struct aws_byte_cursor path_cursor;
- if (aws_http_message_get_request_path(http1_msg, &path_cursor)) {
- AWS_LOGF_ERROR(
- AWS_LS_HTTP_GENERAL,
- "Failed to create HTTP/2 message from HTTP/1 message, ip: %p, due to no path found.",
- (void *)http1_msg);
- aws_raise_error(AWS_ERROR_HTTP_INVALID_PATH);
- goto error;
- }
- if (aws_http_headers_add(copied_headers, aws_http_header_path, path_cursor)) {
- goto error;
- }
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Added header to new HTTP/2 header - \"%.*s\": \"%.*s\" ",
- (int)aws_http_header_path.len,
- aws_http_header_path.ptr,
- (int)path_cursor.len,
- path_cursor.ptr);
- } else {
- int status = 0;
- if (aws_http_message_get_response_status(http1_msg, &status)) {
- AWS_LOGF_ERROR(
- AWS_LS_HTTP_GENERAL,
- "Failed to create HTTP/2 response message from HTTP/1 response message, ip: %p, due to no status "
- "found.",
- (void *)http1_msg);
- /* error will happen when the request is invalid */
- aws_raise_error(AWS_ERROR_HTTP_INVALID_STATUS_CODE);
- goto error;
- }
- if (aws_http2_headers_set_response_status(copied_headers, status)) {
- goto error;
- }
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Added header to new HTTP/2 header - \"%.*s\": \"%d\" ",
- (int)aws_http_header_status.len,
- aws_http_header_status.ptr,
- status);
- }
- if (aws_byte_buf_init(&lower_name_buf, alloc, 256)) {
- goto error;
- }
- for (size_t iter = 0; iter < aws_http_headers_count(old_headers); iter++) {
- aws_byte_buf_reset(&lower_name_buf, false);
- bool copy_header = true;
- /* name should be converted to lower case */
- if (aws_http_headers_get_index(old_headers, iter, &header_iter)) {
- goto error;
- }
- /* append lower case name to the buffer */
- aws_byte_buf_append_with_lookup(&lower_name_buf, &header_iter.name, aws_lookup_table_to_lower_get());
- struct aws_byte_cursor lower_name_cursor = aws_byte_cursor_from_buf(&lower_name_buf);
- enum aws_http_header_name name_enum = aws_http_lowercase_str_to_header_name(lower_name_cursor);
- switch (name_enum) {
- case AWS_HTTP_HEADER_TRANSFER_ENCODING:
- case AWS_HTTP_HEADER_UPGRADE:
- case AWS_HTTP_HEADER_KEEP_ALIVE:
- case AWS_HTTP_HEADER_PROXY_CONNECTION:
- case AWS_HTTP_HEADER_HOST:
- /**
- * An intermediary transforming an HTTP/1.x message to HTTP/2 MUST remove connection-specific header
- * fields as discussed in Section 7.6.1 of [HTTP]. (RFC=9113 8.2.2)
- */
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Skip connection-specific headers - \"%.*s\" ",
- (int)lower_name_cursor.len,
- lower_name_cursor.ptr);
- copy_header = false;
- break;
- default:
- break;
- }
- if (copy_header) {
- if (aws_http_headers_add(copied_headers, lower_name_cursor, header_iter.value)) {
- goto error;
- }
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_GENERAL,
- "Added header to new HTTP/2 header - \"%.*s\": \"%.*s\" ",
- (int)lower_name_cursor.len,
- lower_name_cursor.ptr,
- (int)header_iter.value.len,
- header_iter.value.ptr);
- }
- }
- aws_byte_buf_clean_up(&lower_name_buf);
- aws_http_message_set_body_stream(message, aws_http_message_get_body_stream(http1_msg));
- return message;
- error:
- aws_http_message_release(message);
- aws_byte_buf_clean_up(&lower_name_buf);
- return NULL;
- }
- int aws_http_stream_activate(struct aws_http_stream *stream) {
- AWS_PRECONDITION(stream);
- AWS_PRECONDITION(stream->vtable);
- AWS_PRECONDITION(stream->vtable->activate);
- /* make sure it's actually a client calling us. This is always a programmer bug, so just assert and die. */
- AWS_PRECONDITION(aws_http_connection_is_client(stream->owning_connection));
- return stream->vtable->activate(stream);
- }
- struct aws_http_stream *aws_http_stream_new_server_request_handler(
- const struct aws_http_request_handler_options *options) {
- AWS_PRECONDITION(options);
- if (options->self_size == 0 || !options->server_connection ||
- !aws_http_connection_is_server(options->server_connection)) {
- AWS_LOGF_ERROR(
- AWS_LS_HTTP_CONNECTION,
- "id=%p: Cannot create server request handler stream, options are invalid.",
- (void *)options->server_connection);
- aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- return NULL;
- }
- return options->server_connection->vtable->new_server_request_handler_stream(options);
- }
- int aws_http_stream_send_response(struct aws_http_stream *stream, struct aws_http_message *response) {
- AWS_PRECONDITION(stream);
- AWS_PRECONDITION(response);
- AWS_PRECONDITION(aws_http_message_is_response(response));
- return stream->owning_connection->vtable->stream_send_response(stream, response);
- }
- void aws_http_stream_release(struct aws_http_stream *stream) {
- if (!stream) {
- return;
- }
- size_t prev_refcount = aws_atomic_fetch_sub(&stream->refcount, 1);
- if (prev_refcount == 1) {
- AWS_LOGF_TRACE(AWS_LS_HTTP_STREAM, "id=%p: Final stream refcount released.", (void *)stream);
- void *user_data = stream->user_data;
- aws_http_on_stream_destroy_fn *on_destroy_callback = stream->on_destroy;
- struct aws_http_connection *owning_connection = stream->owning_connection;
- stream->vtable->destroy(stream);
- if (on_destroy_callback) {
- /* info user that destroy completed. */
- on_destroy_callback(user_data);
- }
- /* Connection needed to outlive stream, but it's free to go now */
- aws_http_connection_release(owning_connection);
- } else {
- AWS_ASSERT(prev_refcount != 0);
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_STREAM, "id=%p: Stream refcount released, %zu remaining.", (void *)stream, prev_refcount - 1);
- }
- }
- struct aws_http_connection *aws_http_stream_get_connection(const struct aws_http_stream *stream) {
- AWS_ASSERT(stream);
- return stream->owning_connection;
- }
- int aws_http_stream_get_incoming_response_status(const struct aws_http_stream *stream, int *out_status) {
- AWS_ASSERT(stream && stream->client_data);
- if (stream->client_data->response_status == (int)AWS_HTTP_STATUS_CODE_UNKNOWN) {
- AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Status code not yet received.", (void *)stream);
- return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
- }
- *out_status = stream->client_data->response_status;
- return AWS_OP_SUCCESS;
- }
- int aws_http_stream_get_incoming_request_method(
- const struct aws_http_stream *stream,
- struct aws_byte_cursor *out_method) {
- AWS_ASSERT(stream && stream->server_data);
- if (!stream->server_data->request_method_str.ptr) {
- AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Request method not yet received.", (void *)stream);
- return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
- }
- *out_method = stream->server_data->request_method_str;
- return AWS_OP_SUCCESS;
- }
- int aws_http_stream_get_incoming_request_uri(const struct aws_http_stream *stream, struct aws_byte_cursor *out_uri) {
- AWS_ASSERT(stream && stream->server_data);
- if (!stream->server_data->request_path.ptr) {
- AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Request URI not yet received.", (void *)stream);
- return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
- }
- *out_uri = stream->server_data->request_path;
- return AWS_OP_SUCCESS;
- }
- void aws_http_stream_update_window(struct aws_http_stream *stream, size_t increment_size) {
- stream->vtable->update_window(stream, increment_size);
- }
- uint32_t aws_http_stream_get_id(const struct aws_http_stream *stream) {
- return stream->id;
- }
- int aws_http2_stream_reset(struct aws_http_stream *http2_stream, uint32_t http2_error) {
- AWS_PRECONDITION(http2_stream);
- AWS_PRECONDITION(http2_stream->vtable);
- if (!http2_stream->vtable->http2_reset_stream) {
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_STREAM,
- "id=%p: HTTP/2 stream only function invoked on other stream, ignoring call.",
- (void *)http2_stream);
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- return http2_stream->vtable->http2_reset_stream(http2_stream, http2_error);
- }
- int aws_http2_stream_get_received_reset_error_code(struct aws_http_stream *http2_stream, uint32_t *out_http2_error) {
- AWS_PRECONDITION(http2_stream);
- AWS_PRECONDITION(http2_stream->vtable);
- AWS_PRECONDITION(out_http2_error);
- if (!http2_stream->vtable->http2_get_received_error_code) {
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_STREAM,
- "id=%p: HTTP/2 stream only function invoked on other stream, ignoring call.",
- (void *)http2_stream);
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- return http2_stream->vtable->http2_get_received_error_code(http2_stream, out_http2_error);
- }
- int aws_http2_stream_get_sent_reset_error_code(struct aws_http_stream *http2_stream, uint32_t *out_http2_error) {
- AWS_PRECONDITION(http2_stream);
- AWS_PRECONDITION(http2_stream->vtable);
- AWS_PRECONDITION(out_http2_error);
- if (!http2_stream->vtable->http2_get_sent_error_code) {
- AWS_LOGF_TRACE(
- AWS_LS_HTTP_STREAM,
- "id=%p: HTTP/2 stream only function invoked on other stream, ignoring call.",
- (void *)http2_stream);
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- return http2_stream->vtable->http2_get_sent_error_code(http2_stream, out_http2_error);
- }
|