#ifndef AWS_HTTP_REQUEST_RESPONSE_H #define AWS_HTTP_REQUEST_RESPONSE_H /** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include #include AWS_PUSH_SANE_WARNING_LEVEL struct aws_http_connection; struct aws_input_stream; /** * A stream exists for the duration of a request/response exchange. * A client creates a stream to send a request and receive a response. * A server creates a stream to receive a request and send a response. * In http/2, a push-promise stream can be sent by a server and received by a client. */ struct aws_http_stream; /** * Controls whether a header's strings may be compressed by encoding the index of * strings in a cache, rather than encoding the literal string. * * This setting has no effect on HTTP/1.x connections. * On HTTP/2 connections this controls HPACK behavior. * See RFC-7541 Section 7.1 for security considerations. */ enum aws_http_header_compression { /** * Compress header by encoding the cached index of its strings, * or by updating the cache to contain these strings for future reference. * Best for headers that are sent repeatedly. * This is the default setting. */ AWS_HTTP_HEADER_COMPRESSION_USE_CACHE, /** * Encode header strings literally. * If an intermediary re-broadcasts the headers, it is permitted to use cache. * Best for unique headers that are unlikely to repeat. */ AWS_HTTP_HEADER_COMPRESSION_NO_CACHE, /** * Encode header strings literally and forbid all intermediaries from using * cache when re-broadcasting. * Best for header fields that are highly valuable or sensitive to recovery. */ AWS_HTTP_HEADER_COMPRESSION_NO_FORWARD_CACHE, }; /** * A lightweight HTTP header struct. * Note that the underlying strings are not owned by the byte cursors. */ struct aws_http_header { struct aws_byte_cursor name; struct aws_byte_cursor value; /* Controls whether the header's strings may be compressed via caching. */ enum aws_http_header_compression compression; }; /** * A transformable block of HTTP headers. * Provides a nice API for getting/setting header names and values. * * All strings are copied and stored within this datastructure. * The index of a given header may change any time headers are modified. * When iterating headers, the following ordering rules apply: * * - Headers with the same name will always be in the same order, relative to one another. * If "A: one" is added before "A: two", then "A: one" will always precede "A: two". * * - Headers with different names could be in any order, relative to one another. * If "A: one" is seen before "B: bee" in one iteration, you might see "B: bee" before "A: one" on the next. */ struct aws_http_headers; /** * Header block type. * INFORMATIONAL: Header block for 1xx informational (interim) responses. * MAIN: Main header block sent with request or response. * TRAILING: Headers sent after the body of a request or response. */ enum aws_http_header_block { AWS_HTTP_HEADER_BLOCK_MAIN, AWS_HTTP_HEADER_BLOCK_INFORMATIONAL, AWS_HTTP_HEADER_BLOCK_TRAILING, }; /** * The definition for an outgoing HTTP request or response. * The message may be transformed (ex: signing the request) before its data is eventually sent. * * The message keeps internal copies of its trivial strings (method, path, headers) * but does NOT take ownership of its body stream. * * A language binding would likely present this as an HttpMessage base class with * HttpRequest and HttpResponse subclasses. */ struct aws_http_message; /** * Function to invoke when a message transformation completes. * This function MUST be invoked or the application will soft-lock. * `message` and `complete_ctx` must be the same pointers provided to the `aws_http_message_transform_fn`. * `error_code` should should be AWS_ERROR_SUCCESS if transformation was successful, * otherwise pass a different AWS_ERROR_X value. */ typedef void( aws_http_message_transform_complete_fn)(struct aws_http_message *message, int error_code, void *complete_ctx); /** * A function that may modify a request or response before it is sent. * The transformation may be asynchronous or immediate. * The user MUST invoke the `complete_fn` when transformation is complete or the application will soft-lock. * When invoking the `complete_fn`, pass along the `message` and `complete_ctx` provided here and an error code. * The error code should be AWS_ERROR_SUCCESS if transformation was successful, * otherwise pass a different AWS_ERROR_X value. */ typedef void(aws_http_message_transform_fn)( struct aws_http_message *message, void *user_data, aws_http_message_transform_complete_fn *complete_fn, void *complete_ctx); /** * Invoked repeatedly times as headers are received. * At this point, aws_http_stream_get_incoming_response_status() can be called for the client. * And aws_http_stream_get_incoming_request_method() and aws_http_stream_get_incoming_request_uri() can be called for * the server. * This is always invoked on the HTTP connection's event-loop thread. * * Return AWS_OP_SUCCESS to continue processing the stream. * Return aws_raise_error(E) to indicate failure and cancel the stream. * The error you raise will be reflected in the error_code passed to the on_complete callback. */ typedef int(aws_http_on_incoming_headers_fn)( struct aws_http_stream *stream, enum aws_http_header_block header_block, const struct aws_http_header *header_array, size_t num_headers, void *user_data); /** * Invoked when the incoming header block of this type(informational/main/trailing) has been completely read. * This is always invoked on the HTTP connection's event-loop thread. * * Return AWS_OP_SUCCESS to continue processing the stream. * Return aws_raise_error(E) to indicate failure and cancel the stream. * The error you raise will be reflected in the error_code passed to the on_complete callback. */ typedef int(aws_http_on_incoming_header_block_done_fn)( struct aws_http_stream *stream, enum aws_http_header_block header_block, void *user_data); /** * Called repeatedly as body data is received. * The data must be copied immediately if you wish to preserve it. * This is always invoked on the HTTP connection's event-loop thread. * * Note that, if the connection is using manual_window_management then the window * size has shrunk by the amount of body data received. If the window size * reaches 0 no further data will be received. Increment the window size with * aws_http_stream_update_window(). * * Return AWS_OP_SUCCESS to continue processing the stream. * Return aws_raise_error(E) to indicate failure and cancel the stream. * The error you raise will be reflected in the error_code passed to the on_complete callback. */ typedef int( aws_http_on_incoming_body_fn)(struct aws_http_stream *stream, const struct aws_byte_cursor *data, void *user_data); /** * Invoked when request has been completely read. * This is always invoked on the HTTP connection's event-loop thread. * * Return AWS_OP_SUCCESS to continue processing the stream. * Return aws_raise_error(E) to indicate failure and cancel the stream. * The error you raise will be reflected in the error_code passed to the on_complete callback. */ typedef int(aws_http_on_incoming_request_done_fn)(struct aws_http_stream *stream, void *user_data); /** * Invoked when a request/response stream is complete, whether successful or unsuccessful * This is always invoked on the HTTP connection's event-loop thread. * This will not be invoked if the stream is never activated. */ typedef void(aws_http_on_stream_complete_fn)(struct aws_http_stream *stream, int error_code, void *user_data); /** * Invoked when request/response stream destroy completely. * This can be invoked within the same thead who release the refcount on http stream. * This is invoked even if the stream is never activated. */ typedef void(aws_http_on_stream_destroy_fn)(void *user_data); /** * Tracing metrics for aws_http_stream. * Data maybe not be available if the data of stream was never sent/received before it completes. */ struct aws_http_stream_metrics { /* The time stamp when the request started to be encoded. -1 means data not available. Timestamp * are from `aws_high_res_clock_get_ticks` */ int64_t send_start_timestamp_ns; /* The time stamp when the request finished to be encoded. -1 means data not available. * Timestamp are from `aws_high_res_clock_get_ticks` */ int64_t send_end_timestamp_ns; /* The time duration for the request from start encoding to finish encoding (send_end_timestamp_ns - * send_start_timestamp_ns). -1 means data not available. */ int64_t sending_duration_ns; /* The time stamp when the response started to be received from the network channel. -1 means data not available. * Timestamp are from `aws_high_res_clock_get_ticks` */ int64_t receive_start_timestamp_ns; /* The time stamp when the response finished to be received from the network channel. -1 means data not available. * Timestamp are from `aws_high_res_clock_get_ticks` */ int64_t receive_end_timestamp_ns; /* The time duration for the request from start receiving to finish receiving. receive_end_timestamp_ns - * receive_start_timestamp_ns. -1 means data not available. */ int64_t receiving_duration_ns; /* The stream-id on the connection when this stream was activated. */ uint32_t stream_id; }; /** * Invoked right before request/response stream is complete to report the tracing metrics for aws_http_stream. * This may be invoked synchronously when aws_http_stream_release() is called. * This is invoked even if the stream is never activated. * See `aws_http_stream_metrics` for details. */ typedef void(aws_http_on_stream_metrics_fn)( struct aws_http_stream *stream, const struct aws_http_stream_metrics *metrics, void *user_data); /** * Options for creating a stream which sends a request from the client and receives a response from the server. */ struct aws_http_make_request_options { /** * The sizeof() this struct, used for versioning. * Required. */ size_t self_size; /** * Definition for outgoing request. * Required. * The request will be kept alive via refcounting until the request completes. */ struct aws_http_message *request; void *user_data; /** * Invoked repeatedly times as headers are received. * Optional. * See `aws_http_on_incoming_headers_fn`. */ aws_http_on_incoming_headers_fn *on_response_headers; /** * Invoked when response header block has been completely read. * Optional. * See `aws_http_on_incoming_header_block_done_fn`. */ aws_http_on_incoming_header_block_done_fn *on_response_header_block_done; /** * Invoked repeatedly as body data is received. * Optional. * See `aws_http_on_incoming_body_fn`. */ aws_http_on_incoming_body_fn *on_response_body; /** * Invoked right before stream is complete, whether successful or unsuccessful * Optional. * See `aws_http_on_stream_metrics_fn` */ aws_http_on_stream_metrics_fn *on_metrics; /** * Invoked when request/response stream is complete, whether successful or unsuccessful * Optional. * See `aws_http_on_stream_complete_fn`. */ aws_http_on_stream_complete_fn *on_complete; /* Callback for when the request/response stream is completely destroyed. */ aws_http_on_stream_destroy_fn *on_destroy; /** * When using HTTP/2, request body data will be provided over time. The stream will only be polled for writing * when data has been supplied via `aws_http2_stream_write_data` */ bool http2_use_manual_data_writes; /** * Optional (ignored if 0). * After a request is fully sent, if the server does not begin responding within N milliseconds, then fail with * AWS_ERROR_HTTP_RESPONSE_FIRST_BYTE_TIMEOUT. * It override the connection level settings, when the request completes, the * original monitoring options will be applied back to the connection. * TODO: Only supported in HTTP/1.1 now, support it in HTTP/2 */ uint64_t response_first_byte_timeout_ms; }; struct aws_http_request_handler_options { /* Set to sizeof() this struct, used for versioning. */ size_t self_size; /** * Required. */ struct aws_http_connection *server_connection; /** * user_data passed to callbacks. * Optional. */ void *user_data; /** * Invoked repeatedly times as headers are received. * Optional. * See `aws_http_on_incoming_headers_fn`. */ aws_http_on_incoming_headers_fn *on_request_headers; /** * Invoked when the request header block has been completely read. * Optional. * See `aws_http_on_incoming_header_block_done_fn`. */ aws_http_on_incoming_header_block_done_fn *on_request_header_block_done; /** * Invoked as body data is received. * Optional. * See `aws_http_on_incoming_body_fn`. */ aws_http_on_incoming_body_fn *on_request_body; /** * Invoked when request has been completely read. * Optional. * See `aws_http_on_incoming_request_done_fn`. */ aws_http_on_incoming_request_done_fn *on_request_done; /** * Invoked when request/response stream is complete, whether successful or unsuccessful * Optional. * See `aws_http_on_stream_complete_fn`. */ aws_http_on_stream_complete_fn *on_complete; /* Callback for when the request/response stream is completely destroyed. */ aws_http_on_stream_destroy_fn *on_destroy; }; /** * Invoked when the data stream of an outgoing HTTP write operation is no longer in use. * This is always invoked on the HTTP connection's event-loop thread. * * @param stream HTTP-stream this write operation was submitted to. * @param error_code If error_code is AWS_ERROR_SUCCESS (0), the data was successfully sent. * Any other error_code indicates that the HTTP-stream is in the process of terminating. * If the error_code is AWS_ERROR_HTTP_STREAM_HAS_COMPLETED, * the stream's termination has nothing to do with this write operation. * Any other non-zero error code indicates a problem with this particular write * operation's data. * @param user_data User data for this write operation. */ typedef void aws_http_stream_write_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data); /** * Invoked when the data of an outgoing HTTP/1.1 chunk is no longer in use. * This is always invoked on the HTTP connection's event-loop thread. * * @param stream HTTP-stream this chunk was submitted to. * @param error_code If error_code is AWS_ERROR_SUCCESS (0), the data was successfully sent. * Any other error_code indicates that the HTTP-stream is in the process of terminating. * If the error_code is AWS_ERROR_HTTP_STREAM_HAS_COMPLETED, * the stream's termination has nothing to do with this chunk. * Any other non-zero error code indicates a problem with this particular chunk's data. * @param user_data User data for this chunk. */ typedef aws_http_stream_write_complete_fn aws_http1_stream_write_chunk_complete_fn; /** * HTTP/1.1 chunk extension for chunked encoding. * Note that the underlying strings are not owned by the byte cursors. */ struct aws_http1_chunk_extension { struct aws_byte_cursor key; struct aws_byte_cursor value; }; /** * Encoding options for an HTTP/1.1 chunked transfer encoding chunk. */ struct aws_http1_chunk_options { /* * The data stream to be sent in a single chunk. * The aws_input_stream must remain valid until on_complete is invoked. * May be NULL in the final chunk with size 0. * * Note that, for Transfer-Encodings other than "chunked", the data is * expected to already have that encoding applied. For example, if * "Transfer-Encoding: gzip, chunked" then the data from aws_input_stream * should already be in gzip format. */ struct aws_input_stream *chunk_data; /* * Size of the chunk_data input stream in bytes. */ uint64_t chunk_data_size; /** * A pointer to an array of chunked extensions. * The num_extensions must match the length of the array. * This data is deep-copied by aws_http1_stream_write_chunk(), * it does not need to remain valid until on_complete is invoked. */ struct aws_http1_chunk_extension *extensions; /** * The number of elements defined in the extensions array. */ size_t num_extensions; /** * Invoked when the chunk data is no longer in use, whether or not it was successfully sent. * Optional. * See `aws_http1_stream_write_chunk_complete_fn`. */ aws_http1_stream_write_chunk_complete_fn *on_complete; /** * User provided data passed to the on_complete callback on its invocation. */ void *user_data; }; /** * Invoked when the data of an outgoing HTTP2 data frame is no longer in use. * This is always invoked on the HTTP connection's event-loop thread. * * @param stream HTTP2-stream this write was submitted to. * @param error_code If error_code is AWS_ERROR_SUCCESS (0), the data was successfully sent. * Any other error_code indicates that the HTTP-stream is in the process of terminating. * If the error_code is AWS_ERROR_HTTP_STREAM_HAS_COMPLETED, * the stream's termination has nothing to do with this write. * Any other non-zero error code indicates a problem with this particular write's data. * @param user_data User data for this write. */ typedef aws_http_stream_write_complete_fn aws_http2_stream_write_data_complete_fn; /** * Encoding options for manual H2 data frame writes */ struct aws_http2_stream_write_data_options { /** * The data to be sent. * Optional. * If not set, input stream with length 0 will be used. */ struct aws_input_stream *data; /** * Set true when it's the last chunk to be sent. * After a write with end_stream, no more data write will be accepted. */ bool end_stream; /** * Invoked when the data stream is no longer in use, whether or not it was successfully sent. * Optional. * See `aws_http2_stream_write_data_complete_fn`. */ aws_http2_stream_write_data_complete_fn *on_complete; /** * User provided data passed to the on_complete callback on its invocation. */ void *user_data; }; #define AWS_HTTP_REQUEST_HANDLER_OPTIONS_INIT \ { \ .self_size = sizeof(struct aws_http_request_handler_options), \ } AWS_EXTERN_C_BEGIN /** * Return whether both names are equivalent. * This is a case-insensitive string comparison. * * Example Matches: * "Content-Length" == "content-length" // upper or lower case ok * Example Mismatches: * "Content-Length" != " Content-Length" // leading whitespace bad */ AWS_HTTP_API bool aws_http_header_name_eq(struct aws_byte_cursor name_a, struct aws_byte_cursor name_b); /** * Create a new headers object. * The caller has a hold on the object and must call aws_http_headers_release() when they are done with it. */ AWS_HTTP_API struct aws_http_headers *aws_http_headers_new(struct aws_allocator *allocator); /** * Acquire a hold on the object, preventing it from being deleted until * aws_http_headers_release() is called by all those with a hold on it. */ AWS_HTTP_API void aws_http_headers_acquire(struct aws_http_headers *headers); /** * Release a hold on the object. * The object is deleted when all holds on it are released. */ AWS_HTTP_API void aws_http_headers_release(struct aws_http_headers *headers); /** * Add a header. * The underlying strings are copied. */ AWS_HTTP_API int aws_http_headers_add_header(struct aws_http_headers *headers, const struct aws_http_header *header); /** * Add a header. * The underlying strings are copied. */ AWS_HTTP_API int aws_http_headers_add(struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value); /** * Add an array of headers. * The underlying strings are copied. */ AWS_HTTP_API int aws_http_headers_add_array(struct aws_http_headers *headers, const struct aws_http_header *array, size_t count); /** * Set a header value. * The header is added if necessary and any existing values for this name are removed. * The underlying strings are copied. */ AWS_HTTP_API int aws_http_headers_set(struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value); /** * Get the total number of headers. */ AWS_HTTP_API size_t aws_http_headers_count(const struct aws_http_headers *headers); /** * Get the header at the specified index. * The index of a given header may change any time headers are modified. * When iterating headers, the following ordering rules apply: * * - Headers with the same name will always be in the same order, relative to one another. * If "A: one" is added before "A: two", then "A: one" will always precede "A: two". * * - Headers with different names could be in any order, relative to one another. * If "A: one" is seen before "B: bee" in one iteration, you might see "B: bee" before "A: one" on the next. * * AWS_ERROR_INVALID_INDEX is raised if the index is invalid. */ AWS_HTTP_API int aws_http_headers_get_index( const struct aws_http_headers *headers, size_t index, struct aws_http_header *out_header); /** * * Get all values with this name, combined into one new aws_string that you are responsible for destroying. * If there are multiple headers with this name, their values are appended with comma-separators. * If there are no headers with this name, NULL is returned and AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised. */ AWS_HTTP_API struct aws_string *aws_http_headers_get_all(const struct aws_http_headers *headers, struct aws_byte_cursor name); /** * Get the first value for this name, ignoring any additional values. * AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised if the name is not found. */ AWS_HTTP_API int aws_http_headers_get( const struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor *out_value); /** * Test if header name exists or not in headers */ AWS_HTTP_API bool aws_http_headers_has(const struct aws_http_headers *headers, struct aws_byte_cursor name); /** * Remove all headers with this name. * AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised if no headers with this name are found. */ AWS_HTTP_API int aws_http_headers_erase(struct aws_http_headers *headers, struct aws_byte_cursor name); /** * Remove the first header found with this name and value. * AWS_ERROR_HTTP_HEADER_NOT_FOUND is raised if no such header is found. */ AWS_HTTP_API int aws_http_headers_erase_value( struct aws_http_headers *headers, struct aws_byte_cursor name, struct aws_byte_cursor value); /** * Remove the header at the specified index. * * AWS_ERROR_INVALID_INDEX is raised if the index is invalid. */ AWS_HTTP_API int aws_http_headers_erase_index(struct aws_http_headers *headers, size_t index); /** * Clear all headers. */ AWS_HTTP_API void aws_http_headers_clear(struct aws_http_headers *headers); /** * Get the `:method` value (HTTP/2 headers only). */ AWS_HTTP_API int aws_http2_headers_get_request_method(const struct aws_http_headers *h2_headers, struct aws_byte_cursor *out_method); /** * Set `:method` (HTTP/2 headers only). * The headers makes its own copy of the underlying string. */ AWS_HTTP_API int aws_http2_headers_set_request_method(struct aws_http_headers *h2_headers, struct aws_byte_cursor method); /* * Get the `:scheme` value (HTTP/2 headers only). */ AWS_HTTP_API int aws_http2_headers_get_request_scheme(const struct aws_http_headers *h2_headers, struct aws_byte_cursor *out_scheme); /** * Set `:scheme` (request pseudo headers only). * The pseudo headers makes its own copy of the underlying string. */ AWS_HTTP_API int aws_http2_headers_set_request_scheme(struct aws_http_headers *h2_headers, struct aws_byte_cursor scheme); /* * Get the `:authority` value (request pseudo headers only). */ AWS_HTTP_API int aws_http2_headers_get_request_authority( const struct aws_http_headers *h2_headers, struct aws_byte_cursor *out_authority); /** * Set `:authority` (request pseudo headers only). * The pseudo headers makes its own copy of the underlying string. */ AWS_HTTP_API int aws_http2_headers_set_request_authority(struct aws_http_headers *h2_headers, struct aws_byte_cursor authority); /* * Get the `:path` value (request pseudo headers only). */ AWS_HTTP_API int aws_http2_headers_get_request_path(const struct aws_http_headers *h2_headers, struct aws_byte_cursor *out_path); /** * Set `:path` (request pseudo headers only). * The pseudo headers makes its own copy of the underlying string. */ AWS_HTTP_API int aws_http2_headers_set_request_path(struct aws_http_headers *h2_headers, struct aws_byte_cursor path); /** * Get `:status` (response pseudo headers only). * If no status is set, AWS_ERROR_HTTP_DATA_NOT_AVAILABLE is raised. */ AWS_HTTP_API int aws_http2_headers_get_response_status(const struct aws_http_headers *h2_headers, int *out_status_code); /** * Set `:status` (response pseudo headers only). */ AWS_HTTP_API int aws_http2_headers_set_response_status(struct aws_http_headers *h2_headers, int status_code); /** * Create a new HTTP/1.1 request message. * The message is blank, all properties (method, path, etc) must be set individually. * If HTTP/1.1 message used in HTTP/2 connection, the transformation will be automatically applied. * A HTTP/2 message will created and sent based on the HTTP/1.1 message. * * The caller has a hold on the object and must call aws_http_message_release() when they are done with it. */ AWS_HTTP_API struct aws_http_message *aws_http_message_new_request(struct aws_allocator *allocator); /** * Like aws_http_message_new_request(), but uses existing aws_http_headers instead of creating a new one. * Acquires a hold on the headers, and releases it when the request is destroyed. */ AWS_HTTP_API struct aws_http_message *aws_http_message_new_request_with_headers( struct aws_allocator *allocator, struct aws_http_headers *existing_headers); /** * Create a new HTTP/1.1 response message. * The message is blank, all properties (status, headers, etc) must be set individually. * * The caller has a hold on the object and must call aws_http_message_release() when they are done with it. */ AWS_HTTP_API struct aws_http_message *aws_http_message_new_response(struct aws_allocator *allocator); /** * Create a new HTTP/2 request message. * pseudo headers need to be set from aws_http2_headers_set_request_* to the headers of the aws_http_message. * Will be errored out if used in HTTP/1.1 connection. * * The caller has a hold on the object and must call aws_http_message_release() when they are done with it. */ AWS_HTTP_API struct aws_http_message *aws_http2_message_new_request(struct aws_allocator *allocator); /** * Create a new HTTP/2 response message. * pseudo headers need to be set from aws_http2_headers_set_response_status to the headers of the aws_http_message. * Will be errored out if used in HTTP/1.1 connection. * * The caller has a hold on the object and must call aws_http_message_release() when they are done with it. */ AWS_HTTP_API struct aws_http_message *aws_http2_message_new_response(struct aws_allocator *allocator); /** * Create an HTTP/2 message from HTTP/1.1 message. * pseudo headers will be created from the context and added to the headers of new message. * Normal headers will be copied to the headers of new message. * Note: * - if `host` exist, it will be removed and `:authority` will be added using the information. * - `:scheme` always defaults to "https". To use a different scheme create the HTTP/2 message directly */ AWS_HTTP_API struct aws_http_message *aws_http2_message_new_from_http1( struct aws_allocator *alloc, const struct aws_http_message *http1_msg); /** * Acquire a hold on the object, preventing it from being deleted until * aws_http_message_release() is called by all those with a hold on it. * * This function returns the passed in message (possibly NULL) so that acquire-and-assign can be done with a single * statement. */ AWS_HTTP_API struct aws_http_message *aws_http_message_acquire(struct aws_http_message *message); /** * Release a hold on the object. * The object is deleted when all holds on it are released. * * This function always returns NULL so that release-and-assign-NULL can be done with a single statement. */ AWS_HTTP_API struct aws_http_message *aws_http_message_release(struct aws_http_message *message); /** * Deprecated. This is equivalent to aws_http_message_release(). */ AWS_HTTP_API void aws_http_message_destroy(struct aws_http_message *message); AWS_HTTP_API bool aws_http_message_is_request(const struct aws_http_message *message); AWS_HTTP_API bool aws_http_message_is_response(const struct aws_http_message *message); /** * Get the protocol version of the http message. */ AWS_HTTP_API enum aws_http_version aws_http_message_get_protocol_version(const struct aws_http_message *message); /** * Get the method (request messages only). */ AWS_HTTP_API int aws_http_message_get_request_method( const struct aws_http_message *request_message, struct aws_byte_cursor *out_method); /** * Set the method (request messages only). * The request makes its own copy of the underlying string. */ AWS_HTTP_API int aws_http_message_set_request_method(struct aws_http_message *request_message, struct aws_byte_cursor method); /* * Get the path-and-query value (request messages only). */ AWS_HTTP_API int aws_http_message_get_request_path(const struct aws_http_message *request_message, struct aws_byte_cursor *out_path); /** * Set the path-and-query value (request messages only). * The request makes its own copy of the underlying string. */ AWS_HTTP_API int aws_http_message_set_request_path(struct aws_http_message *request_message, struct aws_byte_cursor path); /** * Get the status code (response messages only). * If no status is set, AWS_ERROR_HTTP_DATA_NOT_AVAILABLE is raised. */ AWS_HTTP_API int aws_http_message_get_response_status(const struct aws_http_message *response_message, int *out_status_code); /** * Set the status code (response messages only). */ AWS_HTTP_API int aws_http_message_set_response_status(struct aws_http_message *response_message, int status_code); /** * Get the body stream. * Returns NULL if no body stream is set. */ AWS_HTTP_API struct aws_input_stream *aws_http_message_get_body_stream(const struct aws_http_message *message); /** * Set the body stream. * NULL is an acceptable value for messages with no body. * Note: The message does NOT take ownership of the body stream. * The stream must not be destroyed until the message is complete. */ AWS_HTTP_API void aws_http_message_set_body_stream(struct aws_http_message *message, struct aws_input_stream *body_stream); /** * aws_future */ AWS_FUTURE_T_POINTER_WITH_RELEASE_DECLARATION(aws_future_http_message, struct aws_http_message, AWS_HTTP_API) /** * Submit a chunk of data to be sent on an HTTP/1.1 stream. * The stream must have specified "chunked" in a "transfer-encoding" header. * For client streams, activate() must be called before any chunks are submitted. * For server streams, the response must be submitted before any chunks. * A final chunk with size 0 must be submitted to successfully complete the HTTP-stream. * * Returns AWS_OP_SUCCESS if the chunk has been submitted. The chunk's completion * callback will be invoked when the HTTP-stream is done with the chunk data, * whether or not it was successfully sent (see `aws_http1_stream_write_chunk_complete_fn`). * The chunk data must remain valid until the completion callback is invoked. * * Returns AWS_OP_ERR and raises an error if the chunk could not be submitted. * In this case, the chunk's completion callback will never be invoked. * Note that it is always possible for the HTTP-stream to terminate unexpectedly * prior to this call being made, in which case the error raised is * AWS_ERROR_HTTP_STREAM_HAS_COMPLETED. */ AWS_HTTP_API int aws_http1_stream_write_chunk( struct aws_http_stream *http1_stream, const struct aws_http1_chunk_options *options); /** * The stream must have specified `http2_use_manual_data_writes` during request creation. * For client streams, activate() must be called before any frames are submitted. * For server streams, the response headers must be submitted before any frames. * A write with options that has end_stream set to be true will end the stream and prevent any further write. * * @return AWS_OP_SUCCESS if the write was queued * AWS_OP_ERROR indicating the attempt raised an error code. * AWS_ERROR_INVALID_STATE will be raised for invalid usage. * AWS_ERROR_HTTP_STREAM_HAS_COMPLETED will be raised if the stream ended for reasons behind the scenes. * * Typical usage will be something like: * options.http2_use_manual_data_writes = true; * stream = aws_http_connection_make_request(connection, &options); * aws_http_stream_activate(stream); * ... * struct aws_http2_stream_write_data_options write; * aws_http2_stream_write_data(stream, &write); * ... * struct aws_http2_stream_write_data_options last_write; * last_write.end_stream = true; * aws_http2_stream_write_data(stream, &write); * ... * aws_http_stream_release(stream); */ AWS_HTTP_API int aws_http2_stream_write_data( struct aws_http_stream *http2_stream, const struct aws_http2_stream_write_data_options *options); /** * Add a list of headers to be added as trailing headers sent after the last chunk is sent. * a "Trailer" header field which indicates the fields present in the trailer. * * Certain headers are forbidden in the trailer (e.g., Transfer-Encoding, Content-Length, Host). See RFC-7541 * Section 4.1.2 for more details. * * For client streams, activate() must be called before any chunks are submitted. * * For server streams, the response must be submitted before the trailer can be added * * aws_http1_stream_add_chunked_trailer must be called before the final size 0 chunk, and at the moment can only * be called once, though this could change if need be. * * Returns AWS_OP_SUCCESS if the chunk has been submitted. */ AWS_HTTP_API int aws_http1_stream_add_chunked_trailer( struct aws_http_stream *http1_stream, const struct aws_http_headers *trailing_headers); /** * * This datastructure has more functions for inspecting and modifying headers than * are available on the aws_http_message datastructure. */ AWS_HTTP_API struct aws_http_headers *aws_http_message_get_headers(const struct aws_http_message *message); /** * Get the message's const aws_http_headers. */ AWS_HTTP_API const struct aws_http_headers *aws_http_message_get_const_headers(const struct aws_http_message *message); /** * Get the number of headers. */ AWS_HTTP_API size_t aws_http_message_get_header_count(const struct aws_http_message *message); /** * Get the header at the specified index. * This function cannot fail if a valid index is provided. * Otherwise, AWS_ERROR_INVALID_INDEX will be raised. * * The underlying strings are stored within the message. */ AWS_HTTP_API int aws_http_message_get_header( const struct aws_http_message *message, struct aws_http_header *out_header, size_t index); /** * Add a header to the end of the array. * The message makes its own copy of the underlying strings. */ AWS_HTTP_API int aws_http_message_add_header(struct aws_http_message *message, struct aws_http_header header); /** * Add an array of headers to the end of the header array. * The message makes its own copy of the underlying strings. * * This is a helper function useful when it's easier to define headers as a stack array, rather than calling add_header * repeatedly. */ AWS_HTTP_API int aws_http_message_add_header_array( struct aws_http_message *message, const struct aws_http_header *headers, size_t num_headers); /** * Remove the header at the specified index. * Headers after this index are all shifted back one position. * * This function cannot fail if a valid index is provided. * Otherwise, AWS_ERROR_INVALID_INDEX will be raised. */ AWS_HTTP_API int aws_http_message_erase_header(struct aws_http_message *message, size_t index); /** * Create a stream, with a client connection sending a request. * The request does not start sending automatically once the stream is created. You must call * aws_http_stream_activate to begin execution of the request. * * The `options` are copied during this call. * * Tip for language bindings: Do not bind the `options` struct. Use something more natural for your language, * such as Builder Pattern in Java, or Python's ability to take many optional arguments by name. * * Note: The header of the request will be sent as it is when the message to send protocol matches the protocol of the * connection. * - No `user-agent` will be added. * - No security check will be enforced. eg: `referer` header privacy should be enforced by the user-agent who adds the * header * - When HTTP/1 message sent on HTTP/2 connection, `aws_http2_message_new_from_http1` will be applied under the hood. * - When HTTP/2 message sent on HTTP/1 connection, no change will be made. */ AWS_HTTP_API struct aws_http_stream *aws_http_connection_make_request( struct aws_http_connection *client_connection, const struct aws_http_make_request_options *options); /** * Create a stream, with a server connection receiving and responding to a request. * This function can only be called from the `aws_http_on_incoming_request_fn` callback. * aws_http_stream_send_response() should be used to send a response. */ AWS_HTTP_API struct aws_http_stream *aws_http_stream_new_server_request_handler( const struct aws_http_request_handler_options *options); /** * Acquire refcount on the stream to prevent it from being cleaned up until it is released. */ AWS_HTTP_API struct aws_http_stream *aws_http_stream_acquire(struct aws_http_stream *stream); /** * Users must release the stream when they are done with it, or its memory will never be cleaned up. * This will not cancel the stream, its callbacks will still fire if the stream is still in progress. * * Tips for language bindings: * - Invoke this from the wrapper class's finalizer/destructor. * - Do not let the wrapper class be destroyed until on_complete() has fired. */ AWS_HTTP_API void aws_http_stream_release(struct aws_http_stream *stream); /** * Only used for client initiated streams (immediately following a call to aws_http_connection_make_request). * * Activates the request's outgoing stream processing. */ AWS_HTTP_API int aws_http_stream_activate(struct aws_http_stream *stream); AWS_HTTP_API struct aws_http_connection *aws_http_stream_get_connection(const struct aws_http_stream *stream); /* Only valid in "request" streams, once response headers start arriving */ AWS_HTTP_API int aws_http_stream_get_incoming_response_status(const struct aws_http_stream *stream, int *out_status); /* Only valid in "request handler" streams, once request headers start arriving */ AWS_HTTP_API int aws_http_stream_get_incoming_request_method( const struct aws_http_stream *stream, struct aws_byte_cursor *out_method); AWS_HTTP_API int aws_http_stream_get_incoming_request_uri(const struct aws_http_stream *stream, struct aws_byte_cursor *out_uri); /** * Send response (only callable from "request handler" streams) * The response object must stay alive at least until the stream's on_complete is called. */ AWS_HTTP_API int aws_http_stream_send_response(struct aws_http_stream *stream, struct aws_http_message *response); /** * Increment the stream's flow-control window to keep data flowing. * * If the connection was created with `manual_window_management` set true, * the flow-control window of each stream will shrink as body data is received * (headers, padding, and other metadata do not affect the window). * The connection's `initial_window_size` determines the starting size of each stream's window. * If a stream's flow-control window reaches 0, no further data will be received. * * If `manual_window_management` is false, this call will have no effect. * The connection maintains its flow-control windows such that * no back-pressure is applied and data arrives as fast as possible. */ AWS_HTTP_API void aws_http_stream_update_window(struct aws_http_stream *stream, size_t increment_size); /** * Gets the HTTP/2 id associated with a stream. Even h1 streams have an id (using the same allocation procedure * as http/2) for easier tracking purposes. For client streams, this will only be non-zero after a successful call * to aws_http_stream_activate() */ AWS_HTTP_API uint32_t aws_http_stream_get_id(const struct aws_http_stream *stream); /** * Cancel the stream in flight. * For HTTP/1.1 streams, it's equivalent to closing the connection. * For HTTP/2 streams, it's equivalent to calling reset on the stream with `AWS_HTTP2_ERR_CANCEL`. * * the stream will complete with the error code provided, unless the stream is * already completing for other reasons, or the stream is not activated, * in which case this call will have no impact. */ AWS_HTTP_API void aws_http_stream_cancel(struct aws_http_stream *stream, int error_code); /** * Reset the HTTP/2 stream (HTTP/2 only). * Note that if the stream closes before this async call is fully processed, the RST_STREAM frame will not be sent. * * @param http2_stream HTTP/2 stream. * @param http2_error aws_http2_error_code. Reason to reset the stream. */ AWS_HTTP_API int aws_http2_stream_reset(struct aws_http_stream *http2_stream, uint32_t http2_error); /** * Get the error code received in rst_stream. * Only valid if the stream has completed, and an RST_STREAM frame has received. * * @param http2_stream HTTP/2 stream. * @param out_http2_error Gets to set to HTTP/2 error code received in rst_stream. */ AWS_HTTP_API int aws_http2_stream_get_received_reset_error_code(struct aws_http_stream *http2_stream, uint32_t *out_http2_error); /** * Get the HTTP/2 error code sent in the RST_STREAM frame (HTTP/2 only). * Only valid if the stream has completed, and has sent an RST_STREAM frame. * * @param http2_stream HTTP/2 stream. * @param out_http2_error Gets to set to HTTP/2 error code sent in rst_stream. */ AWS_HTTP_API int aws_http2_stream_get_sent_reset_error_code(struct aws_http_stream *http2_stream, uint32_t *out_http2_error); AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_REQUEST_RESPONSE_H */