diff options
| author | thegeorg <[email protected]> | 2025-05-12 15:51:24 +0300 |
|---|---|---|
| committer | thegeorg <[email protected]> | 2025-05-12 16:06:27 +0300 |
| commit | d629bb70c8773d2c0c43f5088ddbb5a86d8c37ea (patch) | |
| tree | 4f678e0d65ad08c800db21c657d3b0f71fafed06 /contrib/restricted/aws/aws-c-http | |
| parent | 92c4b696d7a1c03d54e13aff7a7c20a078d90dd7 (diff) | |
Update contrib/restricted/aws libraries to nixpkgs 24.05
commit_hash:f8083acb039e6005e820cdee77b84e0a6b6c6d6d
Diffstat (limited to 'contrib/restricted/aws/aws-c-http')
30 files changed, 544 insertions, 117 deletions
diff --git a/contrib/restricted/aws/aws-c-http/.yandex_meta/override.nix b/contrib/restricted/aws/aws-c-http/.yandex_meta/override.nix index e3d0ccc4c91..5088ed27063 100644 --- a/contrib/restricted/aws/aws-c-http/.yandex_meta/override.nix +++ b/contrib/restricted/aws/aws-c-http/.yandex_meta/override.nix @@ -1,10 +1,10 @@ pkgs: attrs: with pkgs; with attrs; rec { - version = "0.7.6"; + version = "0.8.1"; src = fetchFromGitHub { owner = "awslabs"; repo = "aws-c-http"; rev = "v${version}"; - hash = "sha256-pJGzGbIuz8UJkfmTQEZgXSOMuYixMezNZmgaRlcnmfg="; + hash = "sha256-S5ETVkdGTndt2GJBNL4DU5SycHAufsmN06xBDRMFVKo="; }; } diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/connection.h b/contrib/restricted/aws/aws-c-http/include/aws/http/connection.h index e6362c1439e..031957ef0f1 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/connection.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/connection.h @@ -8,8 +8,11 @@ #include <aws/http/http.h> +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_client_bootstrap; struct aws_socket_options; +struct aws_socket_endpoint; struct aws_tls_connection_options; struct aws_http2_setting; struct proxy_env_var_settings; @@ -269,7 +272,7 @@ struct aws_http_client_connection_options { /** * Required. */ - uint16_t port; + uint32_t port; /** * Required. @@ -305,6 +308,15 @@ struct aws_http_client_connection_options { const struct aws_http_connection_monitoring_options *monitoring_options; /** + * 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. + * This can be overridden per-request by aws_http_make_request_options.response_first_byte_timeout_ms. + * TODO: Only supported in HTTP/1.1 now, support it in HTTP/2 + */ + uint64_t response_first_byte_timeout_ms; + + /** * Set to true to manually manage the flow-control window of each stream. * * If false, the connection will maintain its flow-control windows such that @@ -398,6 +410,12 @@ struct aws_http_client_connection_options { * event loop group associated with the client bootstrap. */ struct aws_event_loop *requested_event_loop; + + /** + * Optional + * Host resolution override that allows the user to override DNS behavior for this particular connection. + */ + const struct aws_host_resolution_config *host_resolution_config; }; /* Predefined settings identifiers (RFC-7540 6.5.2) */ @@ -507,6 +525,12 @@ AWS_HTTP_API struct aws_channel *aws_http_connection_get_channel(struct aws_http_connection *connection); /** + * Returns the remote endpoint of the HTTP connection. + */ +AWS_HTTP_API +const struct aws_socket_endpoint *aws_http_connection_get_remote_endpoint(const struct aws_http_connection *connection); + +/** * Initialize an map copied from the *src map, which maps `struct aws_string *` to `enum aws_http_version`. */ AWS_HTTP_API @@ -675,5 +699,6 @@ AWS_HTTP_API void aws_http2_connection_update_window(struct aws_http_connection *http2_connection, uint32_t increment_size); AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_CONNECTION_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/connection_manager.h b/contrib/restricted/aws/aws-c-http/include/aws/http/connection_manager.h index 4c02df9382a..70b1e77b82d 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/connection_manager.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/connection_manager.h @@ -10,6 +10,8 @@ #include <aws/common/byte_buf.h> +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_client_bootstrap; struct aws_http_connection; struct aws_http_connection_manager; @@ -78,7 +80,7 @@ struct aws_http_connection_manager_options { const struct aws_http_connection_monitoring_options *monitoring_options; struct aws_byte_cursor host; - uint16_t port; + uint32_t port; /** * Optional. @@ -190,5 +192,6 @@ void aws_http_connection_manager_fetch_metrics( struct aws_http_manager_metrics *out_metrics); AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_CONNECTION_MANAGER_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/http.h b/contrib/restricted/aws/aws-c-http/include/aws/http/http.h index f02f09dc3e6..7532537d2f8 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/http.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/http.h @@ -10,6 +10,8 @@ #include <aws/http/exports.h> #include <aws/io/io.h> +AWS_PUSH_SANE_WARNING_LEVEL + #define AWS_C_HTTP_PACKAGE_ID 2 enum aws_http_errors { @@ -57,6 +59,7 @@ enum aws_http_errors { AWS_ERROR_HTTP_WEBSOCKET_PROTOCOL_ERROR, AWS_ERROR_HTTP_MANUAL_WRITE_NOT_ENABLED, AWS_ERROR_HTTP_MANUAL_WRITE_HAS_COMPLETED, + AWS_ERROR_HTTP_RESPONSE_FIRST_BYTE_TIMEOUT, AWS_ERROR_HTTP_END_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_HTTP_PACKAGE_ID) }; @@ -154,5 +157,6 @@ AWS_HTTP_API extern const struct aws_byte_cursor aws_http_scheme_http; AWS_HTTP_API extern const struct aws_byte_cursor aws_http_scheme_https; AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/http2_stream_manager.h b/contrib/restricted/aws/aws-c-http/include/aws/http/http2_stream_manager.h index c37da489aa6..bd78677598b 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/http2_stream_manager.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/http2_stream_manager.h @@ -8,6 +8,8 @@ #include <aws/http/http.h> +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_http2_stream_manager; struct aws_client_bootstrap; struct aws_http_connection; @@ -66,7 +68,7 @@ struct aws_http2_stream_manager_options { bool http2_prior_knowledge; struct aws_byte_cursor host; - uint16_t port; + uint32_t port; /** * Optional. @@ -212,4 +214,6 @@ void aws_http2_stream_manager_fetch_metrics( struct aws_http_manager_metrics *out_metrics); AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL + #endif /* AWS_HTTP2_STREAM_MANAGER_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_impl.h b/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_impl.h index a97ab0daba9..fd9c915ab29 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_impl.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_impl.h @@ -20,10 +20,10 @@ struct aws_http_make_request_options; struct aws_http_request_handler_options; struct aws_http_stream; -typedef int aws_client_bootstrap_new_socket_channel_fn(struct aws_socket_channel_bootstrap_options *options); - +/* vtable of functions that aws_http_connection uses to interact with external systems. + * tests override the vtable to mock those systems */ struct aws_http_connection_system_vtable { - aws_client_bootstrap_new_socket_channel_fn *new_socket_channel; + int (*aws_client_bootstrap_new_socket_channel)(struct aws_socket_channel_bootstrap_options *options); }; struct aws_http_connection_vtable { @@ -103,7 +103,7 @@ struct aws_http_connection { union { struct aws_http_connection_client_data { - uint8_t delete_me; /* exists to prevent "empty struct" errors */ + uint64_t response_first_byte_timeout_ms; } client; struct aws_http_connection_server_data { @@ -133,6 +133,7 @@ struct aws_http_client_bootstrap { aws_http_on_client_connection_setup_fn *on_setup; aws_http_on_client_connection_shutdown_fn *on_shutdown; aws_http_proxy_request_transform_fn *proxy_request_transform; + uint64_t response_first_byte_timeout_ms; struct aws_http1_connection_options http1_options; struct aws_http2_connection_options http2_options; /* allocated with bootstrap */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_manager_system_vtable.h b/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_manager_system_vtable.h index 115ba661364..d5d183b82ed 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_manager_system_vtable.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/private/connection_manager_system_vtable.h @@ -12,28 +12,20 @@ struct aws_http_connection_manager; -typedef int(aws_http_connection_manager_create_connection_fn)(const struct aws_http_client_connection_options *options); -typedef void(aws_http_connection_manager_close_connection_fn)(struct aws_http_connection *connection); -typedef void(aws_http_connection_release_connection_fn)(struct aws_http_connection *connection); -typedef bool(aws_http_connection_is_connection_available_fn)(const struct aws_http_connection *connection); -typedef bool(aws_http_connection_manager_is_callers_thread_fn)(struct aws_channel *channel); -typedef struct aws_channel *(aws_http_connection_manager_connection_get_channel_fn)( - struct aws_http_connection *connection); -typedef enum aws_http_version(aws_http_connection_manager_connection_get_version_fn)( - const struct aws_http_connection *connection); - +/* vtable of functions that aws_http_connection_manager uses to interact with external systems. + * tests override the vtable to mock those systems */ struct aws_http_connection_manager_system_vtable { /* * Downstream http functions */ - aws_http_connection_manager_create_connection_fn *create_connection; - aws_http_connection_manager_close_connection_fn *close_connection; - aws_http_connection_release_connection_fn *release_connection; - aws_http_connection_is_connection_available_fn *is_connection_available; - aws_io_clock_fn *get_monotonic_time; - aws_http_connection_manager_is_callers_thread_fn *is_callers_thread; - aws_http_connection_manager_connection_get_channel_fn *connection_get_channel; - aws_http_connection_manager_connection_get_version_fn *connection_get_version; + int (*aws_http_client_connect)(const struct aws_http_client_connection_options *options); + void (*aws_http_connection_close)(struct aws_http_connection *connection); + void (*aws_http_connection_release)(struct aws_http_connection *connection); + bool (*aws_http_connection_new_requests_allowed)(const struct aws_http_connection *connection); + int (*aws_high_res_clock_get_ticks)(uint64_t *timestamp); + bool (*aws_channel_thread_is_callers_thread)(struct aws_channel *channel); + struct aws_channel *(*aws_http_connection_get_channel)(struct aws_http_connection *connection); + enum aws_http_version (*aws_http_connection_get_version)(const struct aws_http_connection *connection); }; AWS_HTTP_API diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/private/h1_stream.h b/contrib/restricted/aws/aws-c-http/include/aws/http/private/h1_stream.h index df1446ec9b3..8b210c8b1dd 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/private/h1_stream.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/private/h1_stream.h @@ -117,6 +117,7 @@ struct aws_h1_stream *aws_h1_stream_new_request( struct aws_h1_stream *aws_h1_stream_new_request_handler(const struct aws_http_request_handler_options *options); int aws_h1_stream_activate(struct aws_http_stream *stream); +void aws_h1_stream_cancel(struct aws_http_stream *stream, int error_code); int aws_h1_stream_send_response(struct aws_h1_stream *stream, struct aws_http_message *response); diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/private/h2_connection.h b/contrib/restricted/aws/aws-c-http/include/aws/http/private/h2_connection.h index 6d42b831602..f2754ab754d 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/private/h2_connection.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/private/h2_connection.h @@ -125,6 +125,7 @@ struct aws_h2_connection { uint64_t outgoing_timestamp_ns; /* Timestamp when connection has data to receive, which is when there is an active stream */ uint64_t incoming_timestamp_ns; + } thread_data; /* Any thread may touch this data, but the lock must be held (unless it's an atomic) */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/private/proxy_impl.h b/contrib/restricted/aws/aws-c-http/include/aws/http/private/proxy_impl.h index c47305b251e..946fece72b3 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/private/proxy_impl.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/private/proxy_impl.h @@ -52,7 +52,7 @@ struct aws_http_proxy_config { struct aws_byte_buf host; - uint16_t port; + uint32_t port; struct aws_tls_connection_options *tls_options; @@ -97,7 +97,7 @@ struct aws_http_proxy_user_data { * Cached original connect options */ struct aws_string *original_host; - uint16_t original_port; + uint32_t original_port; void *original_user_data; struct aws_tls_connection_options *original_tls_options; struct aws_client_bootstrap *original_bootstrap; @@ -126,10 +126,16 @@ struct aws_http_proxy_user_data { struct aws_http_proxy_config *proxy_config; struct aws_event_loop *requested_event_loop; + + const struct aws_host_resolution_config *host_resolution_config; }; +/* vtable of functions that proxy uses to interact with external systems. + * tests override the vtable to mock those systems */ struct aws_http_proxy_system_vtable { - int (*setup_client_tls)(struct aws_channel_slot *right_of_slot, struct aws_tls_connection_options *tls_options); + int (*aws_channel_setup_client_tls)( + struct aws_channel_slot *right_of_slot, + struct aws_tls_connection_options *tls_options); }; AWS_EXTERN_C_BEGIN diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/private/request_response_impl.h b/contrib/restricted/aws/aws-c-http/include/aws/http/private/request_response_impl.h index 9cd06e01c24..acc5d9dd7db 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/private/request_response_impl.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/private/request_response_impl.h @@ -6,6 +6,7 @@ * SPDX-License-Identifier: Apache-2.0. */ +#include <aws/common/task_scheduler.h> #include <aws/http/request_response.h> #include <aws/http/private/http_impl.h> @@ -16,6 +17,7 @@ struct aws_http_stream_vtable { void (*destroy)(struct aws_http_stream *stream); void (*update_window)(struct aws_http_stream *stream, size_t increment_size); int (*activate)(struct aws_http_stream *stream); + void (*cancel)(struct aws_http_stream *stream, int error_code); int (*http1_write_chunk)(struct aws_http_stream *http1_stream, const struct aws_http1_chunk_options *options); int (*http1_add_trailer)(struct aws_http_stream *http1_stream, const struct aws_http_headers *trailing_headers); @@ -43,15 +45,21 @@ struct aws_http_stream { aws_http_on_incoming_headers_fn *on_incoming_headers; aws_http_on_incoming_header_block_done_fn *on_incoming_header_block_done; aws_http_on_incoming_body_fn *on_incoming_body; + aws_http_on_stream_metrics_fn *on_metrics; aws_http_on_stream_complete_fn *on_complete; aws_http_on_stream_destroy_fn *on_destroy; struct aws_atomic_var refcount; enum aws_http_method request_method; + struct aws_http_stream_metrics metrics; union { struct aws_http_stream_client_data { int response_status; + uint64_t response_first_byte_timeout_ms; + /* Using aws_task instead of aws_channel_task because, currently, channel-tasks can't be canceled. + * We only touch this from the connection's thread */ + struct aws_task response_first_byte_timeout_task; } client; struct aws_http_stream_server_data { struct aws_byte_cursor request_method_str; diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/proxy.h b/contrib/restricted/aws/aws-c-http/include/aws/http/proxy.h index cd4c92107df..28fdfb045b5 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/proxy.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/proxy.h @@ -11,6 +11,8 @@ #include <aws/http/request_response.h> #include <aws/http/status_code.h> +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_http_client_connection_options; struct aws_http_connection_manager_options; @@ -112,7 +114,7 @@ struct aws_http_proxy_options { /** * Port to make the proxy connection to */ - uint16_t port; + uint32_t port; /** * Optional. @@ -566,5 +568,6 @@ AWS_HTTP_API int aws_http_proxy_new_socket_channel( const struct aws_http_proxy_options *proxy_options); AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_PROXY_STRATEGY_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/request_response.h b/contrib/restricted/aws/aws-c-http/include/aws/http/request_response.h index a4ff6da9477..73c1900508f 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/request_response.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/request_response.h @@ -8,6 +8,10 @@ #include <aws/http/http.h> +#include <aws/io/future.h> + +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_http_connection; struct aws_input_stream; @@ -135,7 +139,8 @@ typedef void(aws_http_message_transform_fn)( * This is always invoked on the HTTP connection's event-loop thread. * * Return AWS_OP_SUCCESS to continue processing the stream. - * Return AWS_OP_ERR to indicate failure and cancel 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, @@ -149,7 +154,8 @@ typedef int(aws_http_on_incoming_headers_fn)( * This is always invoked on the HTTP connection's event-loop thread. * * Return AWS_OP_SUCCESS to continue processing the stream. - * Return AWS_OP_ERR to indicate failure and cancel 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, @@ -167,7 +173,8 @@ typedef int(aws_http_on_incoming_header_block_done_fn)( * aws_http_stream_update_window(). * * Return AWS_OP_SUCCESS to continue processing the stream. - * Return AWS_OP_ERR to indicate failure and cancel 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); @@ -177,24 +184,66 @@ typedef int( * This is always invoked on the HTTP connection's event-loop thread. * * Return AWS_OP_SUCCESS to continue processing the stream. - * Return AWS_OP_ERR to indicate failure and cancel 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 request/response stream is completely destroyed. - * This may be invoked synchronously when aws_http_stream_release() is called. - * This is invoked even if the stream is never activated. + * 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 { @@ -235,6 +284,13 @@ struct aws_http_make_request_options { 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`. @@ -249,6 +305,16 @@ struct aws_http_make_request_options { * 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 { @@ -807,6 +873,11 @@ AWS_HTTP_API void aws_http_message_set_body_stream(struct aws_http_message *message, struct aws_input_stream *body_stream); /** + * aws_future<aws_http_message*> + */ +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. @@ -973,6 +1044,12 @@ 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. * @@ -1038,6 +1115,18 @@ 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. * @@ -1068,5 +1157,6 @@ 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 */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/server.h b/contrib/restricted/aws/aws-c-http/include/aws/http/server.h index 0e1be3d8c01..03893355d8a 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/server.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/server.h @@ -8,6 +8,8 @@ #include <aws/http/http.h> +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_http_connection; struct aws_server_bootstrap; struct aws_socket_options; @@ -193,6 +195,13 @@ int aws_http_connection_configure_server( AWS_HTTP_API bool aws_http_connection_is_server(const struct aws_http_connection *connection); +/** + * Returns the local listener endpoint of the HTTP server. Only valid as long as the server remains valid. + */ +AWS_HTTP_API +const struct aws_socket_endpoint *aws_http_server_get_listener_endpoint(const struct aws_http_server *server); + AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_SERVER_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/statistics.h b/contrib/restricted/aws/aws-c-http/include/aws/http/statistics.h index ecc8c2700ab..7f3790242e0 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/statistics.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/statistics.h @@ -10,6 +10,8 @@ #include <aws/common/statistics.h> +AWS_PUSH_SANE_WARNING_LEVEL + enum aws_crt_http_statistics_category { AWSCRT_STAT_CAT_HTTP1_CHANNEL = AWS_CRT_STATISTICS_CATEGORY_BEGIN_RANGE(AWS_C_HTTP_PACKAGE_ID), AWSCRT_STAT_CAT_HTTP2_CHANNEL, @@ -71,5 +73,6 @@ AWS_HTTP_API void aws_crt_statistics_http2_channel_reset(struct aws_crt_statistics_http2_channel *stats); AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_STATISTICS_H */ diff --git a/contrib/restricted/aws/aws-c-http/include/aws/http/websocket.h b/contrib/restricted/aws/aws-c-http/include/aws/http/websocket.h index 6f85cafa810..39703b4e2bb 100644 --- a/contrib/restricted/aws/aws-c-http/include/aws/http/websocket.h +++ b/contrib/restricted/aws/aws-c-http/include/aws/http/websocket.h @@ -7,6 +7,8 @@ #include <aws/http/http.h> +AWS_PUSH_SANE_WARNING_LEVEL + struct aws_http_header; struct aws_http_message; @@ -183,7 +185,7 @@ struct aws_websocket_client_connection_options { * Optional. * Defaults to 443 if tls_options is present, 80 if it is not. */ - uint16_t port; + uint32_t port; /** * Required. @@ -280,6 +282,12 @@ struct aws_websocket_client_connection_options { * a single thread. */ struct aws_event_loop *requested_event_loop; + + /** + * Optional + * Host resolution override that allows the user to override DNS behavior for this particular connection. + */ + const struct aws_host_resolution_config *host_resolution_config; }; /** @@ -479,5 +487,6 @@ struct aws_http_message *aws_http_message_new_websocket_handshake_request( struct aws_byte_cursor host); AWS_EXTERN_C_END +AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_HTTP_WEBSOCKET_H */ diff --git a/contrib/restricted/aws/aws-c-http/source/connection.c b/contrib/restricted/aws/aws-c-http/source/connection.c index f020823dcf1..a53aebe1912 100644 --- a/contrib/restricted/aws/aws-c-http/source/connection.c +++ b/contrib/restricted/aws/aws-c-http/source/connection.c @@ -18,6 +18,7 @@ #include <aws/io/channel_bootstrap.h> #include <aws/io/logging.h> #include <aws/io/socket.h> +#include <aws/io/socket_channel_handler.h> #include <aws/io/tls_channel_handler.h> #ifdef _MSC_VER @@ -26,7 +27,7 @@ #endif static struct aws_http_connection_system_vtable s_default_system_vtable = { - .new_socket_channel = aws_client_bootstrap_new_socket_channel, + .aws_client_bootstrap_new_socket_channel = aws_client_bootstrap_new_socket_channel, }; static const struct aws_http_connection_system_vtable *s_system_vtable_ptr = &s_default_system_vtable; @@ -366,6 +367,16 @@ struct aws_channel *aws_http_connection_get_channel(struct aws_http_connection * return connection->channel_slot->channel; } +const struct aws_socket_endpoint *aws_http_connection_get_remote_endpoint( + const struct aws_http_connection *connection) { + AWS_ASSERT(connection); + struct aws_channel *channel = connection->channel_slot->channel; + /* The first slot for an HTTP connection is always socket */ + struct aws_channel_slot *socket_slot = aws_channel_get_first_slot(channel); + const struct aws_socket *socket = aws_socket_handler_get_socket(socket_slot->handler); + return &socket->remote_endpoint; +} + int aws_http_alpn_map_init(struct aws_allocator *allocator, struct aws_hash_table *map) { AWS_ASSERT(allocator); AWS_ASSERT(map); @@ -495,7 +506,7 @@ static void s_server_bootstrap_on_accept_channel_setup( if (put_err) { AWS_LOGF_ERROR( AWS_LS_HTTP_SERVER, - "%p: %s:%d: Failed to store connection object, error %d (%s).", + "%p: %s:%u: Failed to store connection object, error %d (%s).", (void *)server, server->socket->local_endpoint.address, server->socket->local_endpoint.port, @@ -508,7 +519,7 @@ static void s_server_bootstrap_on_accept_channel_setup( /* Tell user of successful connection. */ AWS_LOGF_INFO( AWS_LS_HTTP_CONNECTION, - "id=%p: " PRInSTR " server connection established at %p %s:%d.", + "id=%p: " PRInSTR " server connection established at %p %s:%u.", (void *)connection, AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(connection->http_version)), (void *)server, @@ -690,7 +701,7 @@ struct aws_http_server *aws_http_server_new(const struct aws_http_server_options AWS_LOGF_INFO( AWS_LS_HTTP_SERVER, - "%p %s:%d: Server setup complete, listening for incoming connections.", + "%p %s:%u: Server setup complete, listening for incoming connections.", (void *)server, server->socket->local_endpoint.address, server->socket->local_endpoint.port); @@ -740,7 +751,7 @@ void aws_http_server_release(struct aws_http_server *server) { * s_server_bootstrap_on_server_listener_destroy will be invoked, clean up of the server will be there */ AWS_LOGF_INFO( AWS_LS_HTTP_SERVER, - "%p %s:%d: Shutting down the server.", + "%p %s:%u: Shutting down the server.", (void *)server, server->socket->local_endpoint.address, server->socket->local_endpoint.port); @@ -751,6 +762,12 @@ void aws_http_server_release(struct aws_http_server *server) { * clean up will be called from eventloop */ } +const struct aws_socket_endpoint *aws_http_server_get_listener_endpoint(const struct aws_http_server *server) { + AWS_FATAL_ASSERT(server); + + return &server->socket->local_endpoint; +} + /* At this point, the channel bootstrapper has established a connection to the server and set up a channel. * Now we need to create the aws_http_connection and insert it into the channel as a channel-handler. */ static void s_client_bootstrap_on_channel_setup( @@ -823,6 +840,8 @@ static void s_client_bootstrap_on_channel_setup( } http_bootstrap->connection->proxy_request_transform = http_bootstrap->proxy_request_transform; + http_bootstrap->connection->client_data->response_first_byte_timeout_ms = + http_bootstrap->response_first_byte_timeout_ms; AWS_LOGF_INFO( AWS_LS_HTTP_CONNECTION, @@ -1062,6 +1081,7 @@ int aws_http_client_connect_internal( http_bootstrap->proxy_request_transform = proxy_request_transform; http_bootstrap->http1_options = *options.http1_options; http_bootstrap->http2_options = *options.http2_options; + http_bootstrap->response_first_byte_timeout_ms = options.response_first_byte_timeout_ms; /* keep a copy of the settings array if it's not NULL */ if (options.http2_options->num_initial_settings > 0) { @@ -1085,9 +1105,9 @@ int aws_http_client_connect_internal( AWS_LOGF_TRACE( AWS_LS_HTTP_CONNECTION, - "static: attempting to initialize a new client channel to %s:%d", + "static: attempting to initialize a new client channel to %s:%u", aws_string_c_str(host_name), - (int)options.port); + options.port); struct aws_socket_channel_bootstrap_options channel_options = { .bootstrap = options.bootstrap, @@ -1100,9 +1120,10 @@ int aws_http_client_connect_internal( .enable_read_back_pressure = options.manual_window_management, .user_data = http_bootstrap, .requested_event_loop = options.requested_event_loop, + .host_resolution_override_config = options.host_resolution_config, }; - err = s_system_vtable_ptr->new_socket_channel(&channel_options); + err = s_system_vtable_ptr->aws_client_bootstrap_new_socket_channel(&channel_options); if (err) { AWS_LOGF_ERROR( diff --git a/contrib/restricted/aws/aws-c-http/source/connection_manager.c b/contrib/restricted/aws/aws-c-http/source/connection_manager.c index 30eda61778f..195a7d6caf6 100644 --- a/contrib/restricted/aws/aws-c-http/source/connection_manager.c +++ b/contrib/restricted/aws/aws-c-http/source/connection_manager.c @@ -43,22 +43,22 @@ struct aws_idle_connection { * System vtable to use under normal circumstances */ static struct aws_http_connection_manager_system_vtable s_default_system_vtable = { - .create_connection = aws_http_client_connect, - .release_connection = aws_http_connection_release, - .close_connection = aws_http_connection_close, - .is_connection_available = aws_http_connection_new_requests_allowed, - .get_monotonic_time = aws_high_res_clock_get_ticks, - .is_callers_thread = aws_channel_thread_is_callers_thread, - .connection_get_channel = aws_http_connection_get_channel, - .connection_get_version = aws_http_connection_get_version, + .aws_http_client_connect = aws_http_client_connect, + .aws_http_connection_release = aws_http_connection_release, + .aws_http_connection_close = aws_http_connection_close, + .aws_http_connection_new_requests_allowed = aws_http_connection_new_requests_allowed, + .aws_high_res_clock_get_ticks = aws_high_res_clock_get_ticks, + .aws_channel_thread_is_callers_thread = aws_channel_thread_is_callers_thread, + .aws_http_connection_get_channel = aws_http_connection_get_channel, + .aws_http_connection_get_version = aws_http_connection_get_version, }; const struct aws_http_connection_manager_system_vtable *g_aws_http_connection_manager_default_system_vtable_ptr = &s_default_system_vtable; bool aws_http_connection_manager_system_vtable_is_valid(const struct aws_http_connection_manager_system_vtable *table) { - return table->create_connection && table->close_connection && table->release_connection && - table->is_connection_available; + return table->aws_http_client_connect && table->aws_http_connection_close && table->aws_http_connection_release && + table->aws_http_connection_new_requests_allowed; } enum aws_http_connection_manager_state_type { AWS_HCMST_UNINITIALIZED, AWS_HCMST_READY, AWS_HCMST_SHUTTING_DOWN }; @@ -236,7 +236,7 @@ struct aws_http_connection_manager { struct aws_string *host; struct proxy_env_var_settings proxy_ev_settings; struct aws_tls_connection_options *proxy_ev_tls_options; - uint16_t port; + uint32_t port; /* * HTTP/2 specific. */ @@ -433,13 +433,13 @@ static void s_aws_http_connection_manager_complete_acquisitions( if (pending_acquisition->error_code == AWS_OP_SUCCESS) { - struct aws_channel *channel = - pending_acquisition->manager->system_vtable->connection_get_channel(pending_acquisition->connection); + struct aws_channel *channel = pending_acquisition->manager->system_vtable->aws_http_connection_get_channel( + pending_acquisition->connection); AWS_PRECONDITION(channel); /* For some workloads, going ahead and moving the connection callback to the connection's thread is a * substantial performance improvement so let's do that */ - if (!pending_acquisition->manager->system_vtable->is_callers_thread(channel)) { + if (!pending_acquisition->manager->system_vtable->aws_channel_thread_is_callers_thread(channel)) { aws_channel_task_init( &pending_acquisition->acquisition_task, s_connection_acquisition_task, @@ -776,7 +776,7 @@ static void s_schedule_connection_culling(struct aws_http_connection_manager *ma * culling interval from now. */ uint64_t now = 0; - manager->system_vtable->get_monotonic_time(&now); + manager->system_vtable->aws_high_res_clock_get_ticks(&now); cull_task_time = now + aws_timestamp_convert( manager->max_connection_idle_in_milliseconds, AWS_TIMESTAMP_MILLIS, AWS_TIMESTAMP_NANOS, NULL); @@ -1024,7 +1024,7 @@ static int s_aws_http_connection_manager_new_connection(struct aws_http_connecti options.proxy_options = &proxy_options; } - if (manager->system_vtable->create_connection(&options)) { + if (manager->system_vtable->aws_http_client_connect(&options)) { AWS_LOGF_ERROR( AWS_LS_HTTP_CONNECTION_MANAGER, "id=%p: http connection creation failed with error code %d(%s)", @@ -1061,7 +1061,7 @@ static void s_aws_http_connection_manager_execute_transaction(struct aws_connect "id=%p: Releasing connection (id=%p)", (void *)manager, (void *)idle_connection->connection); - manager->system_vtable->release_connection(idle_connection->connection); + manager->system_vtable->aws_http_connection_release(idle_connection->connection); aws_mem_release(idle_connection->allocator, idle_connection); } @@ -1071,7 +1071,7 @@ static void s_aws_http_connection_manager_execute_transaction(struct aws_connect "id=%p: Releasing connection (id=%p)", (void *)manager, (void *)work->connection_to_release); - manager->system_vtable->release_connection(work->connection_to_release); + manager->system_vtable->aws_http_connection_release(work->connection_to_release); } /* @@ -1194,7 +1194,7 @@ static int s_idle_connection(struct aws_http_connection_manager *manager, struct idle_connection->connection = connection; uint64_t idle_start_timestamp = 0; - if (manager->system_vtable->get_monotonic_time(&idle_start_timestamp)) { + if (manager->system_vtable->aws_high_res_clock_get_ticks(&idle_start_timestamp)) { goto on_error; } @@ -1223,7 +1223,7 @@ int aws_http_connection_manager_release_connection( s_aws_connection_management_transaction_init(&work, manager); int result = AWS_OP_ERR; - bool should_release_connection = !manager->system_vtable->is_connection_available(connection); + bool should_release_connection = !manager->system_vtable->aws_http_connection_new_requests_allowed(connection); AWS_LOGF_DEBUG( AWS_LS_HTTP_CONNECTION_MANAGER, @@ -1413,7 +1413,8 @@ static void s_aws_http_connection_manager_on_connection_setup( s_connection_manager_internal_ref_increase(manager, AWS_HCMCT_OPEN_CONNECTION, 1); } - if (connection != NULL && manager->system_vtable->connection_get_version(connection) == AWS_HTTP_VERSION_2) { + if (connection != NULL && + manager->system_vtable->aws_http_connection_get_version(connection) == AWS_HTTP_VERSION_2) { /* If the manager is shutting down, we will still wait for the settings, since we don't have map for connections */ ++manager->pending_settings_count; @@ -1492,7 +1493,7 @@ static void s_cull_idle_connections(struct aws_http_connection_manager *manager) } uint64_t now = 0; - if (manager->system_vtable->get_monotonic_time(&now)) { + if (manager->system_vtable->aws_high_res_clock_get_ticks(&now)) { return; } diff --git a/contrib/restricted/aws/aws-c-http/source/h1_connection.c b/contrib/restricted/aws/aws-c-http/source/h1_connection.c index 3532bb80d94..903cf038144 100644 --- a/contrib/restricted/aws/aws-c-http/source/h1_connection.c +++ b/contrib/restricted/aws/aws-c-http/source/h1_connection.c @@ -11,6 +11,7 @@ #include <aws/http/private/h1_stream.h> #include <aws/http/private/request_response_impl.h> #include <aws/http/status_code.h> +#include <aws/io/event_loop.h> #include <aws/io/logging.h> #include <inttypes.h> @@ -371,6 +372,7 @@ int aws_h1_stream_activate(struct aws_http_stream *stream) { /* connection keeps activated stream alive until stream completes */ aws_atomic_fetch_add(&stream->refcount, 1); + stream->metrics.stream_id = stream->id; if (should_schedule_task) { AWS_LOGF_TRACE( @@ -386,6 +388,34 @@ int aws_h1_stream_activate(struct aws_http_stream *stream) { return AWS_OP_SUCCESS; } +void aws_h1_stream_cancel(struct aws_http_stream *stream, int error_code) { + struct aws_h1_stream *h1_stream = AWS_CONTAINER_OF(stream, struct aws_h1_stream, base); + struct aws_http_connection *base_connection = stream->owning_connection; + struct aws_h1_connection *connection = AWS_CONTAINER_OF(base_connection, struct aws_h1_connection, base); + + { /* BEGIN CRITICAL SECTION */ + aws_h1_connection_lock_synced_data(connection); + if (h1_stream->synced_data.api_state != AWS_H1_STREAM_API_STATE_ACTIVE || + connection->synced_data.is_open == false) { + /* Not active, nothing to cancel. */ + aws_h1_connection_unlock_synced_data(connection); + AWS_LOGF_DEBUG(AWS_LS_HTTP_STREAM, "id=%p: Stream not active, nothing to cancel.", (void *)stream); + return; + } + + aws_h1_connection_unlock_synced_data(connection); + } /* END CRITICAL SECTION */ + AWS_LOGF_INFO( + AWS_LS_HTTP_CONNECTION, + "id=%p: Connection shutting down due to stream=%p cancelled with error code %d (%s).", + (void *)&connection->base, + (void *)stream, + error_code, + aws_error_name(error_code)); + + s_stop(connection, false /*stop_reading*/, false /*stop_writing*/, true /*schedule_shutdown*/, error_code); +} + struct aws_http_stream *s_make_request( struct aws_http_connection *client_connection, const struct aws_http_make_request_options *options) { @@ -534,6 +564,7 @@ static int s_aws_http1_switch_protocols(struct aws_h1_connection *connection) { static void s_stream_complete(struct aws_h1_stream *stream, int error_code) { struct aws_h1_connection *connection = AWS_CONTAINER_OF(stream->base.owning_connection, struct aws_h1_connection, base); + AWS_ASSERT(aws_channel_thread_is_callers_thread(connection->base.channel_slot->channel)); /* * If this is the end of a successful CONNECT request, mark ourselves as pass-through since the proxy layer @@ -546,6 +577,14 @@ static void s_stream_complete(struct aws_h1_stream *stream, int error_code) { } } + if (stream->base.client_data && stream->base.client_data->response_first_byte_timeout_task.fn != NULL) { + /* There is an outstanding response timeout task, but stream completed, we can cancel it now. We are + * safe to do it as we always on connection thread to schedule the task or cancel it */ + struct aws_event_loop *connection_loop = aws_channel_get_event_loop(connection->base.channel_slot->channel); + /* The task will be zeroed out within the call */ + aws_event_loop_cancel_task(connection_loop, &stream->base.client_data->response_first_byte_timeout_task); + } + if (error_code != AWS_ERROR_SUCCESS) { if (stream->base.client_data && stream->is_incoming_message_done) { /* As a request that finished receiving the response, we ignore error and @@ -633,6 +672,10 @@ static void s_stream_complete(struct aws_h1_stream *stream, int error_code) { aws_h1_chunk_complete_and_destroy(chunk, &stream->base, AWS_ERROR_HTTP_STREAM_HAS_COMPLETED); } + if (stream->base.on_metrics) { + stream->base.on_metrics(&stream->base, &stream->base.metrics, stream->base.user_data); + } + /* Invoke callback and clean up stream. */ if (stream->base.on_complete) { stream->base.on_complete(&stream->base, error_code, stream->base.user_data); @@ -716,6 +759,87 @@ static void s_client_update_incoming_stream_ptr(struct aws_h1_connection *connec s_set_incoming_stream_ptr(connection, desired); } +static void s_http_stream_response_first_byte_timeout_task( + struct aws_task *task, + void *arg, + enum aws_task_status status) { + (void)task; + struct aws_h1_stream *stream = arg; + struct aws_http_connection *connection_base = stream->base.owning_connection; + /* zero-out task to indicate that it's no longer scheduled */ + AWS_ZERO_STRUCT(stream->base.client_data->response_first_byte_timeout_task); + + if (status == AWS_TASK_STATUS_CANCELED) { + return; + } + + struct aws_h1_connection *connection = AWS_CONTAINER_OF(connection_base, struct aws_h1_connection, base); + /* Timeout happened, close the connection */ + uint64_t response_first_byte_timeout_ms = stream->base.client_data->response_first_byte_timeout_ms == 0 + ? connection_base->client_data->response_first_byte_timeout_ms + : stream->base.client_data->response_first_byte_timeout_ms; + AWS_LOGF_INFO( + AWS_LS_HTTP_CONNECTION, + "id=%p: Closing connection as timeout after request sent to the first byte received happened. " + "response_first_byte_timeout_ms is %" PRIu64 ".", + (void *)connection_base, + response_first_byte_timeout_ms); + + /* Don't stop reading/writing immediately, let that happen naturally during the channel shutdown process. */ + s_stop( + connection, + false /*stop_reading*/, + false /*stop_writing*/, + true /*schedule_shutdown*/, + AWS_ERROR_HTTP_RESPONSE_FIRST_BYTE_TIMEOUT); +} + +static void s_set_outgoing_message_done(struct aws_h1_stream *stream) { + struct aws_http_connection *connection = stream->base.owning_connection; + struct aws_channel *channel = aws_http_connection_get_channel(connection); + AWS_ASSERT(aws_channel_thread_is_callers_thread(channel)); + + if (stream->is_outgoing_message_done) { + /* Already did the job */ + return; + } + + stream->is_outgoing_message_done = true; + AWS_ASSERT(stream->base.metrics.send_end_timestamp_ns == -1); + aws_high_res_clock_get_ticks((uint64_t *)&stream->base.metrics.send_end_timestamp_ns); + AWS_ASSERT(stream->base.metrics.send_start_timestamp_ns != -1); + AWS_ASSERT(stream->base.metrics.send_end_timestamp_ns >= stream->base.metrics.send_start_timestamp_ns); + stream->base.metrics.sending_duration_ns = + stream->base.metrics.send_end_timestamp_ns - stream->base.metrics.send_start_timestamp_ns; + if (stream->base.metrics.receive_start_timestamp_ns == -1) { + /* We haven't receive any message, schedule the response timeout task */ + + uint64_t response_first_byte_timeout_ms = 0; + if (stream->base.client_data != NULL && connection->client_data != NULL) { + response_first_byte_timeout_ms = stream->base.client_data->response_first_byte_timeout_ms == 0 + ? connection->client_data->response_first_byte_timeout_ms + : stream->base.client_data->response_first_byte_timeout_ms; + } + if (response_first_byte_timeout_ms != 0) { + /* The task should not be initialized before. */ + AWS_ASSERT(stream->base.client_data->response_first_byte_timeout_task.fn == NULL); + aws_task_init( + &stream->base.client_data->response_first_byte_timeout_task, + s_http_stream_response_first_byte_timeout_task, + stream, + "http_stream_response_first_byte_timeout_task"); + uint64_t now_ns = 0; + aws_channel_current_clock_time(channel, &now_ns); + struct aws_event_loop *connection_loop = aws_channel_get_event_loop(channel); + aws_event_loop_schedule_task_future( + connection_loop, + &stream->base.client_data->response_first_byte_timeout_task, + now_ns + aws_timestamp_convert( + response_first_byte_timeout_ms, AWS_TIMESTAMP_MILLIS, AWS_TIMESTAMP_NANOS, NULL)); + } + } +} + /** * If necessary, update `outgoing_stream` so it is pointing at a stream * with data to send, or NULL if all streams are done sending data. @@ -730,7 +854,7 @@ static struct aws_h1_stream *s_update_outgoing_stream_ptr(struct aws_h1_connecti /* If current stream is done sending data... */ if (current && !aws_h1_encoder_is_message_in_progress(&connection->thread_data.encoder)) { - current->is_outgoing_message_done = true; + s_set_outgoing_message_done(current); /* RFC-7230 section 6.6: Tear-down. * If this was the final stream, don't allows any further streams to be sent */ @@ -801,9 +925,13 @@ static struct aws_h1_stream *s_update_outgoing_stream_ptr(struct aws_h1_connecti s_set_outgoing_stream_ptr(connection, current); if (current) { + AWS_ASSERT(current->base.metrics.send_start_timestamp_ns == -1); + aws_high_res_clock_get_ticks((uint64_t *)¤t->base.metrics.send_start_timestamp_ns); + err = aws_h1_encoder_start_message( &connection->thread_data.encoder, ¤t->encoder_message, ¤t->base); (void)err; + AWS_ASSERT(connection->thread_data.encoder.state == AWS_H1_ENCODER_STATE_INIT); AWS_ASSERT(!err); } @@ -1109,7 +1237,7 @@ static int s_decoder_on_header(const struct aws_h1_decoded_header *header, void AWS_LS_HTTP_STREAM, "id=%p: Received 'Connection: close' header, no more request data will be sent.", (void *)&incoming_stream->base); - incoming_stream->is_outgoing_message_done = true; + s_set_outgoing_message_done(incoming_stream); } /* Stop writing right now. * Shutdown will be scheduled after we finishing parsing the response */ @@ -1270,6 +1398,13 @@ static int s_decoder_on_done(void *user_data) { /* Otherwise the incoming stream is finished decoding and we will update it if needed */ incoming_stream->is_incoming_message_done = true; + aws_high_res_clock_get_ticks((uint64_t *)&incoming_stream->base.metrics.receive_end_timestamp_ns); + AWS_ASSERT(incoming_stream->base.metrics.receive_start_timestamp_ns != -1); + AWS_ASSERT( + incoming_stream->base.metrics.receive_end_timestamp_ns >= + incoming_stream->base.metrics.receive_start_timestamp_ns); + incoming_stream->base.metrics.receiving_duration_ns = incoming_stream->base.metrics.receive_end_timestamp_ns - + incoming_stream->base.metrics.receive_start_timestamp_ns; /* RFC-7230 section 6.6 * After reading the final message, the connection must not read any more */ @@ -1822,6 +1957,20 @@ static int s_try_process_next_stream_read_message(struct aws_h1_connection *conn bool body_headers_ignored = incoming_stream->base.request_method == AWS_HTTP_METHOD_HEAD; aws_h1_decoder_set_body_headers_ignored(connection->thread_data.incoming_stream_decoder, body_headers_ignored); + if (incoming_stream->base.metrics.receive_start_timestamp_ns == -1) { + /* That's the first time for the stream receives any message */ + aws_high_res_clock_get_ticks((uint64_t *)&incoming_stream->base.metrics.receive_start_timestamp_ns); + if (incoming_stream->base.client_data && + incoming_stream->base.client_data->response_first_byte_timeout_task.fn != NULL) { + /* There is an outstanding response timeout task, as we already received the data, we can cancel it now. We + * are safe to do it as we always on connection thread to schedule the task or cancel it */ + struct aws_event_loop *connection_loop = aws_channel_get_event_loop(connection->base.channel_slot->channel); + /* The task will be zeroed out within the call */ + aws_event_loop_cancel_task( + connection_loop, &incoming_stream->base.client_data->response_first_byte_timeout_task); + } + } + /* As decoder runs, it invokes the internal s_decoder_X callbacks, which in turn invoke user callbacks. * The decoder will stop once it hits the end of the request/response OR the end of the message data. */ if (aws_h1_decode(connection->thread_data.incoming_stream_decoder, &message_cursor)) { diff --git a/contrib/restricted/aws/aws-c-http/source/h1_decoder.c b/contrib/restricted/aws/aws-c-http/source/h1_decoder.c index 68e5aa224ae..c615d09a658 100644 --- a/contrib/restricted/aws/aws-c-http/source/h1_decoder.c +++ b/contrib/restricted/aws/aws-c-http/source/h1_decoder.c @@ -301,7 +301,7 @@ static int s_linestate_chunk_size(struct aws_h1_decoder *decoder, struct aws_byt decoder->logging_id, AWS_BYTE_CURSOR_PRI(input)); - return AWS_OP_ERR; + return aws_raise_error(AWS_ERROR_HTTP_PROTOCOL_ERROR); } int err = aws_byte_cursor_utf8_parse_u64_hex(size, &decoder->chunk_size); diff --git a/contrib/restricted/aws/aws-c-http/source/h1_encoder.c b/contrib/restricted/aws/aws-c-http/source/h1_encoder.c index 1899d2f4025..277dce94633 100644 --- a/contrib/restricted/aws/aws-c-http/source/h1_encoder.c +++ b/contrib/restricted/aws/aws-c-http/source/h1_encoder.c @@ -403,10 +403,7 @@ int aws_h1_encoder_message_init_from_response( goto error; } - err = aws_byte_buf_init(&message->outgoing_head_buf, allocator, head_total_len); - if (err) { - return AWS_OP_ERR; - } + aws_byte_buf_init(&message->outgoing_head_buf, allocator, head_total_len); bool wrote_all = true; @@ -489,9 +486,9 @@ static size_t s_calculate_chunk_line_size(const struct aws_http1_chunk_options * size_t chunk_line_size = MAX_ASCII_HEX_CHUNK_STR_SIZE + CRLF_SIZE; for (size_t i = 0; i < options->num_extensions; ++i) { struct aws_http1_chunk_extension *chunk_extension = options->extensions + i; - chunk_line_size += sizeof(';'); + chunk_line_size += 1 /* ; */; chunk_line_size += chunk_extension->key.len; - chunk_line_size += sizeof('='); + chunk_line_size += 1 /* = */; chunk_line_size += chunk_extension->value.len; } return chunk_line_size; diff --git a/contrib/restricted/aws/aws-c-http/source/h1_stream.c b/contrib/restricted/aws/aws-c-http/source/h1_stream.c index a5d2f4782b4..ef8f086bfca 100644 --- a/contrib/restricted/aws/aws-c-http/source/h1_stream.c +++ b/contrib/restricted/aws/aws-c-http/source/h1_stream.c @@ -329,6 +329,7 @@ static const struct aws_http_stream_vtable s_stream_vtable = { .destroy = s_stream_destroy, .update_window = s_stream_update_window, .activate = aws_h1_stream_activate, + .cancel = aws_h1_stream_cancel, .http1_write_chunk = s_stream_write_chunk, .http1_add_trailer = s_stream_add_trailer, .http2_reset_stream = NULL, @@ -361,6 +362,12 @@ static struct aws_h1_stream *s_stream_new_common( stream->base.on_incoming_body = on_incoming_body; stream->base.on_complete = on_complete; stream->base.on_destroy = on_destroy; + stream->base.metrics.send_start_timestamp_ns = -1; + stream->base.metrics.send_end_timestamp_ns = -1; + stream->base.metrics.sending_duration_ns = -1; + stream->base.metrics.receive_start_timestamp_ns = -1; + stream->base.metrics.receive_end_timestamp_ns = -1; + stream->base.metrics.receiving_duration_ns = -1; aws_channel_task_init( &stream->cross_thread_work_task, s_stream_cross_thread_work_task, stream, "http1_stream_cross_thread_work"); @@ -401,6 +408,8 @@ struct aws_h1_stream *aws_h1_stream_new_request( stream->base.client_data = &stream->base.client_or_server_data.client; stream->base.client_data->response_status = AWS_HTTP_STATUS_CODE_UNKNOWN; + stream->base.client_data->response_first_byte_timeout_ms = options->response_first_byte_timeout_ms; + stream->base.on_metrics = options->on_metrics; /* Validate request and cache info that the encoder will eventually need */ if (aws_h1_encoder_message_init_from_request( diff --git a/contrib/restricted/aws/aws-c-http/source/h2_connection.c b/contrib/restricted/aws/aws-c-http/source/h2_connection.c index 15ea192f8ab..f27c005f38f 100644 --- a/contrib/restricted/aws/aws-c-http/source/h2_connection.c +++ b/contrib/restricted/aws/aws-c-http/source/h2_connection.c @@ -1531,7 +1531,7 @@ static struct aws_h2err s_decoder_on_settings_ack(void *userdata) { } connection->thread_data.settings_self[settings_array[i].id] = settings_array[i].value; } - /* invoke the change settings compeleted user callback */ + /* invoke the change settings completed user callback */ if (pending_settings->on_completed) { pending_settings->on_completed(&connection->base, AWS_ERROR_SUCCESS, pending_settings->user_data); } @@ -2057,6 +2057,7 @@ int aws_h2_stream_activate(struct aws_http_stream *stream) { /* connection keeps activated stream alive until stream completes */ aws_atomic_fetch_add(&stream->refcount, 1); + stream->metrics.stream_id = stream->id; if (!was_cross_thread_work_scheduled) { CONNECTION_LOG(TRACE, connection, "Scheduling cross-thread work task"); diff --git a/contrib/restricted/aws/aws-c-http/source/h2_stream.c b/contrib/restricted/aws/aws-c-http/source/h2_stream.c index 85232db0066..6d8336bfd3d 100644 --- a/contrib/restricted/aws/aws-c-http/source/h2_stream.c +++ b/contrib/restricted/aws/aws-c-http/source/h2_stream.c @@ -5,6 +5,7 @@ #include <aws/http/private/h2_stream.h> +#include <aws/common/clock.h> #include <aws/http/private/h2_connection.h> #include <aws/http/private/strutil.h> #include <aws/http/status_code.h> @@ -26,12 +27,17 @@ static int s_stream_write_data( static void s_stream_cross_thread_work_task(struct aws_channel_task *task, void *arg, enum aws_task_status status); static struct aws_h2err s_send_rst_and_close_stream(struct aws_h2_stream *stream, struct aws_h2err stream_error); -static int s_stream_reset_stream_internal(struct aws_http_stream *stream_base, struct aws_h2err stream_error); +static int s_stream_reset_stream_internal( + struct aws_http_stream *stream_base, + struct aws_h2err stream_error, + bool cancelling); +static void s_stream_cancel(struct aws_http_stream *stream, int error_code); struct aws_http_stream_vtable s_h2_stream_vtable = { .destroy = s_stream_destroy, .update_window = s_stream_update_window, .activate = aws_h2_stream_activate, + .cancel = s_stream_cancel, .http1_write_chunk = NULL, .http2_reset_stream = s_stream_reset_stream, .http2_get_received_error_code = s_stream_get_received_error_code, @@ -240,10 +246,17 @@ struct aws_h2_stream *aws_h2_stream_new_request( stream->base.on_incoming_headers = options->on_response_headers; stream->base.on_incoming_header_block_done = options->on_response_header_block_done; stream->base.on_incoming_body = options->on_response_body; + stream->base.on_metrics = options->on_metrics; stream->base.on_complete = options->on_complete; stream->base.on_destroy = options->on_destroy; stream->base.client_data = &stream->base.client_or_server_data.client; stream->base.client_data->response_status = AWS_HTTP_STATUS_CODE_UNKNOWN; + stream->base.metrics.send_start_timestamp_ns = -1; + stream->base.metrics.send_end_timestamp_ns = -1; + stream->base.metrics.sending_duration_ns = -1; + stream->base.metrics.receive_start_timestamp_ns = -1; + stream->base.metrics.receive_end_timestamp_ns = -1; + stream->base.metrics.receiving_duration_ns = -1; aws_linked_list_init(&stream->thread_data.outgoing_writes); aws_linked_list_init(&stream->synced_data.pending_write_list); @@ -446,6 +459,9 @@ void aws_h2_stream_complete(struct aws_h2_stream *stream, int error_code) { s_h2_stream_destroy_pending_writes(stream); /* Invoke callback */ + if (stream->base.on_metrics) { + stream->base.on_metrics(&stream->base, &stream->base.metrics, stream->base.user_data); + } if (stream->base.on_complete) { stream->base.on_complete(&stream->base, error_code, stream->base.user_data); } @@ -515,12 +531,16 @@ static void s_stream_update_window(struct aws_http_stream *stream_base, size_t i .h2_code = AWS_HTTP2_ERR_INTERNAL_ERROR, }; /* Only when stream is not initialized reset will fail. So, we can assert it to be succeed. */ - AWS_FATAL_ASSERT(s_stream_reset_stream_internal(stream_base, stream_error) == AWS_OP_SUCCESS); + AWS_FATAL_ASSERT( + s_stream_reset_stream_internal(stream_base, stream_error, false /*cancelling*/) == AWS_OP_SUCCESS); } return; } -static int s_stream_reset_stream_internal(struct aws_http_stream *stream_base, struct aws_h2err stream_error) { +static int s_stream_reset_stream_internal( + struct aws_http_stream *stream_base, + struct aws_h2err stream_error, + bool cancelling) { struct aws_h2_stream *stream = AWS_CONTAINER_OF(stream_base, struct aws_h2_stream, base); struct aws_h2_connection *connection = s_get_h2_connection(stream); @@ -542,21 +562,25 @@ static int s_stream_reset_stream_internal(struct aws_http_stream *stream_base, s } /* END CRITICAL SECTION */ if (stream_is_init) { + if (cancelling) { + /* Not an error if we are just cancelling. */ + AWS_LOGF_DEBUG(AWS_LS_HTTP_STREAM, "id=%p: Stream not in process, nothing to cancel.", (void *)stream); + return AWS_OP_SUCCESS; + } AWS_H2_STREAM_LOG( ERROR, stream, "Reset stream failed. Stream is in initialized state, please activate the stream first."); return aws_raise_error(AWS_ERROR_INVALID_STATE); } + if (reset_called) { + AWS_H2_STREAM_LOG(DEBUG, stream, "Reset stream ignored. Reset stream has been called already."); + } + if (cross_thread_work_should_schedule) { AWS_H2_STREAM_LOG(TRACE, stream, "Scheduling stream cross-thread work task"); /* increment the refcount of stream to keep it alive until the task runs */ aws_atomic_fetch_add(&stream->base.refcount, 1); aws_channel_schedule_task_now(connection->base.channel_slot->channel, &stream->cross_thread_work_task); - return AWS_OP_SUCCESS; } - if (reset_called) { - AWS_H2_STREAM_LOG(DEBUG, stream, "Reset stream ignored. Reset stream has been called already."); - } - return AWS_OP_SUCCESS; } @@ -572,7 +596,16 @@ static int s_stream_reset_stream(struct aws_http_stream *stream_base, uint32_t h (void *)stream_base, aws_http2_error_code_to_str(http2_error), http2_error); - return s_stream_reset_stream_internal(stream_base, stream_error); + return s_stream_reset_stream_internal(stream_base, stream_error, false /*cancelling*/); +} + +void s_stream_cancel(struct aws_http_stream *stream_base, int error_code) { + struct aws_h2err stream_error = { + .aws_code = error_code, + .h2_code = AWS_HTTP2_ERR_CANCEL, + }; + s_stream_reset_stream_internal(stream_base, stream_error, true /*cancelling*/); + return; } static int s_stream_get_received_error_code(struct aws_http_stream *stream_base, uint32_t *out_http2_error) { @@ -706,7 +739,8 @@ int aws_h2_stream_on_activated(struct aws_h2_stream *stream, enum aws_h2_stream_ AWS_H2_STREAM_LOGF(ERROR, stream, "Failed to create HEADERS frame: %s", aws_error_name(aws_last_error())); goto error; } - + AWS_ASSERT(stream->base.metrics.send_start_timestamp_ns == -1); + aws_high_res_clock_get_ticks((uint64_t *)&stream->base.metrics.send_start_timestamp_ns); /* Initialize the flow-control window size */ stream->thread_data.window_size_peer = connection->thread_data.settings_peer[AWS_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; @@ -721,6 +755,11 @@ int aws_h2_stream_on_activated(struct aws_h2_stream *stream, enum aws_h2_stream_ /* If stream has no body, then HEADERS frame marks the end of outgoing data */ stream->thread_data.state = AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL; AWS_H2_STREAM_LOG(TRACE, stream, "Sending HEADERS with END_STREAM. State -> HALF_CLOSED_LOCAL"); + /* There is no further frames to be sent, now is the end timestamp of sending. */ + AWS_ASSERT(stream->base.metrics.send_end_timestamp_ns == -1); + aws_high_res_clock_get_ticks((uint64_t *)&stream->base.metrics.send_end_timestamp_ns); + stream->base.metrics.sending_duration_ns = + stream->base.metrics.send_end_timestamp_ns - stream->base.metrics.send_start_timestamp_ns; } if (s_h2_stream_has_outgoing_writes(stream)) { @@ -798,6 +837,11 @@ int aws_h2_stream_encode_data_frame( */ if (input_stream_complete && ends_stream) { /* Done sending data. No more data will be sent. */ + AWS_ASSERT(stream->base.metrics.send_end_timestamp_ns == -1); + aws_high_res_clock_get_ticks((uint64_t *)&stream->base.metrics.send_end_timestamp_ns); + stream->base.metrics.sending_duration_ns = + stream->base.metrics.send_end_timestamp_ns - stream->base.metrics.send_start_timestamp_ns; + if (stream->thread_data.state == AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE) { /* Both sides have sent END_STREAM */ stream->thread_data.state = AWS_H2_STREAM_STATE_CLOSED; @@ -841,6 +885,7 @@ struct aws_h2err aws_h2_stream_on_decoder_headers_begin(struct aws_h2_stream *st if (aws_h2err_failed(stream_err)) { return s_send_rst_and_close_stream(stream, stream_err); } + aws_high_res_clock_get_ticks((uint64_t *)&stream->base.metrics.receive_start_timestamp_ns); return AWS_H2ERR_SUCCESS; } @@ -1150,6 +1195,13 @@ struct aws_h2err aws_h2_stream_on_decoder_end_stream(struct aws_h2_stream *strea * an actual frame type. It's a flag on DATA or HEADERS frames, and we * already checked the legality of those frames in their respective callbacks. */ + AWS_ASSERT(stream->base.metrics.receive_start_timestamp_ns != -1); + AWS_ASSERT(stream->base.metrics.receive_end_timestamp_ns == -1); + aws_high_res_clock_get_ticks((uint64_t *)&stream->base.metrics.receive_end_timestamp_ns); + AWS_ASSERT(stream->base.metrics.receive_end_timestamp_ns >= stream->base.metrics.receive_start_timestamp_ns); + stream->base.metrics.receiving_duration_ns = + stream->base.metrics.receive_end_timestamp_ns - stream->base.metrics.receive_start_timestamp_ns; + if (stream->thread_data.content_length_received) { if (stream->base.request_method != AWS_HTTP_METHOD_HEAD && stream->base.client_data->response_status != AWS_HTTP_STATUS_CODE_304_NOT_MODIFIED) { diff --git a/contrib/restricted/aws/aws-c-http/source/hpack.c b/contrib/restricted/aws/aws-c-http/source/hpack.c index ef3d0b3dcfa..83aee646782 100644 --- a/contrib/restricted/aws/aws-c-http/source/hpack.c +++ b/contrib/restricted/aws/aws-c-http/source/hpack.c @@ -103,7 +103,7 @@ void aws_hpack_static_table_init(struct aws_allocator *allocator) { } } -void aws_hpack_static_table_clean_up() { +void aws_hpack_static_table_clean_up(void) { aws_hash_table_clean_up(&s_static_header_reverse_lookup); aws_hash_table_clean_up(&s_static_header_reverse_lookup_name_only); } diff --git a/contrib/restricted/aws/aws-c-http/source/http.c b/contrib/restricted/aws/aws-c-http/source/http.c index 8a8fe92bd19..af61c51517a 100644 --- a/contrib/restricted/aws/aws-c-http/source/http.c +++ b/contrib/restricted/aws/aws-c-http/source/http.c @@ -148,6 +148,9 @@ static struct aws_error_info s_errors[] = { AWS_DEFINE_ERROR_INFO_HTTP( AWS_ERROR_HTTP_MANUAL_WRITE_HAS_COMPLETED, "Manual write failed because manual writes are already completed."), + AWS_DEFINE_ERROR_INFO_HTTP( + AWS_ERROR_HTTP_RESPONSE_FIRST_BYTE_TIMEOUT, + "The server does not begin responding within the configuration after a request is fully sent."), }; /* clang-format on */ @@ -537,7 +540,7 @@ void aws_http_library_clean_up(void) { aws_io_library_clean_up(); } -void aws_http_fatal_assert_library_initialized() { +void aws_http_fatal_assert_library_initialized(void) { if (!s_library_initialized) { AWS_LOGF_FATAL( AWS_LS_HTTP_GENERAL, diff --git a/contrib/restricted/aws/aws-c-http/source/proxy_connection.c b/contrib/restricted/aws/aws-c-http/source/proxy_connection.c index e6cdb8a2460..3706c2fd543 100644 --- a/contrib/restricted/aws/aws-c-http/source/proxy_connection.c +++ b/contrib/restricted/aws/aws-c-http/source/proxy_connection.c @@ -39,7 +39,7 @@ AWS_STATIC_STRING_FROM_LITERAL(s_proxy_no_verify_peer_env_var, "AWS_PROXY_NO_VER #endif static struct aws_http_proxy_system_vtable s_default_vtable = { - .setup_client_tls = &aws_channel_setup_client_tls, + .aws_channel_setup_client_tls = &aws_channel_setup_client_tls, }; static struct aws_http_proxy_system_vtable *s_vtable = &s_default_vtable; @@ -162,6 +162,7 @@ struct aws_http_proxy_user_data *aws_http_proxy_user_data_new( user_data->original_channel_on_setup = on_channel_setup; user_data->original_channel_on_shutdown = on_channel_shutdown; user_data->requested_event_loop = options.requested_event_loop; + user_data->host_resolution_config = options.host_resolution_config; user_data->prior_knowledge_http2 = options.prior_knowledge_http2; /* one and only one setup callback must be valid */ @@ -465,7 +466,7 @@ static struct aws_http_message *s_build_h1_proxy_connect_request(struct aws_http } char port_str[20] = "\0"; - snprintf(port_str, sizeof(port_str), "%d", (int)user_data->original_port); + snprintf(port_str, sizeof(port_str), "%u", user_data->original_port); struct aws_byte_cursor port_cursor = aws_byte_cursor_from_c_str(port_str); if (aws_byte_buf_append(&path_buffer, &port_cursor)) { goto on_error; @@ -771,7 +772,7 @@ static void s_aws_http_on_stream_complete_tunnel_proxy( last_slot = last_slot->adj_right; } - if (s_vtable->setup_client_tls(last_slot, context->original_tls_options)) { + if (s_vtable->aws_channel_setup_client_tls(last_slot, context->original_tls_options)) { AWS_LOGF_ERROR( AWS_LS_HTTP_CONNECTION, "(%p) Proxy connection failed to start TLS negotiation with error %d(%s)", @@ -1048,6 +1049,7 @@ static int s_aws_http_client_connect_via_forwarding_proxy(const struct aws_http_ options_copy.on_shutdown = s_aws_http_on_client_connection_http_proxy_shutdown_fn; options_copy.tls_options = options->proxy_options->tls_options; options_copy.requested_event_loop = options->requested_event_loop; + options_copy.host_resolution_config = options->host_resolution_config; options_copy.prior_knowledge_http2 = false; /* ToDo, expose the protocol specific config for proxy connection. */ int result = aws_http_client_connect_internal(&options_copy, s_proxy_http_request_transform); @@ -1084,6 +1086,7 @@ static int s_create_tunneling_connection(struct aws_http_proxy_user_data *user_d connect_options.http1_options = NULL; /* ToDo, expose the protocol specific config for proxy connection. */ connect_options.http2_options = NULL; /* ToDo */ connect_options.requested_event_loop = user_data->requested_event_loop; + connect_options.host_resolution_config = user_data->host_resolution_config; int result = aws_http_client_connect(&connect_options); if (result == AWS_OP_ERR) { @@ -1137,6 +1140,23 @@ static enum aws_http_proxy_connection_type s_determine_proxy_connection_type( } } +static struct aws_string *s_get_proxy_environment_value( + struct aws_allocator *allocator, + const struct aws_string *env_name) { + struct aws_string *out_string = NULL; + if (aws_get_environment_value(allocator, env_name, &out_string) == AWS_OP_SUCCESS && out_string != NULL && + out_string->len > 0) { + AWS_LOGF_DEBUG( + AWS_LS_HTTP_CONNECTION, + "%s environment found, %s", + aws_string_c_str(env_name), + aws_string_c_str(out_string)); + return out_string; + } + aws_string_destroy(out_string); + return NULL; +} + static int s_proxy_uri_init_from_env_variable( struct aws_allocator *allocator, const struct aws_http_client_connection_options *options, @@ -1145,25 +1165,19 @@ static int s_proxy_uri_init_from_env_variable( struct aws_string *proxy_uri_string = NULL; *found = false; if (options->tls_options) { - if (aws_get_environment_value(allocator, s_https_proxy_env_var_low, &proxy_uri_string) == AWS_OP_SUCCESS && - proxy_uri_string != NULL) { - AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "https_proxy environment found"); - } else if ( - aws_get_environment_value(allocator, s_https_proxy_env_var, &proxy_uri_string) == AWS_OP_SUCCESS && - proxy_uri_string != NULL) { - AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "HTTPS_PROXY environment found"); - } else { + proxy_uri_string = s_get_proxy_environment_value(allocator, s_https_proxy_env_var_low); + if (proxy_uri_string == NULL) { + proxy_uri_string = s_get_proxy_environment_value(allocator, s_https_proxy_env_var); + } + if (proxy_uri_string == NULL) { return AWS_OP_SUCCESS; } } else { - if (aws_get_environment_value(allocator, s_http_proxy_env_var_low, &proxy_uri_string) == AWS_OP_SUCCESS && - proxy_uri_string != NULL) { - AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "http_proxy environment found"); - } else if ( - aws_get_environment_value(allocator, s_http_proxy_env_var, &proxy_uri_string) == AWS_OP_SUCCESS && - proxy_uri_string != NULL) { - AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "HTTP_PROXY environment found"); - } else { + proxy_uri_string = s_get_proxy_environment_value(allocator, s_http_proxy_env_var_low); + if (proxy_uri_string == NULL) { + proxy_uri_string = s_get_proxy_environment_value(allocator, s_http_proxy_env_var); + } + if (proxy_uri_string == NULL) { return AWS_OP_SUCCESS; } } @@ -1213,7 +1227,7 @@ static int s_setup_proxy_tls_env_variable( AWS_LS_HTTP_CONNECTION, "Failed making default TLS context because of BYO_CRYPTO, set up the tls_options for proxy_env_settings to " "make it work."); - return AWS_OP_ERR; + return aws_raise_error(AWS_ERROR_UNIMPLEMENTED); #else struct aws_tls_ctx *tls_ctx = NULL; struct aws_tls_ctx_options tls_ctx_options; @@ -1642,6 +1656,7 @@ int aws_http_proxy_new_socket_channel( http_connection_options.on_setup = NULL; /* use channel callbacks, not http callbacks */ http_connection_options.on_shutdown = NULL; /* use channel callbacks, not http callbacks */ http_connection_options.requested_event_loop = channel_options->requested_event_loop; + http_connection_options.host_resolution_config = channel_options->host_resolution_override_config; if (s_aws_http_client_connect_via_tunneling_proxy( &http_connection_options, s_http_proxied_socket_channel_setup, s_http_proxied_socket_channel_shutdown)) { diff --git a/contrib/restricted/aws/aws-c-http/source/request_response.c b/contrib/restricted/aws/aws-c-http/source/request_response.c index c382a3a4d0e..dbd5214e762 100644 --- a/contrib/restricted/aws/aws-c-http/source/request_response.c +++ b/contrib/restricted/aws/aws-c-http/source/request_response.c @@ -867,6 +867,11 @@ int aws_http_message_get_header( return aws_http_headers_get_index(message->headers, index, out_header); } +AWS_FUTURE_T_POINTER_WITH_RELEASE_IMPLEMENTATION( + aws_future_http_message, + struct aws_http_message, + aws_http_message_release) + struct aws_http_stream *aws_http_connection_make_request( struct aws_http_connection *client_connection, const struct aws_http_make_request_options *options) { @@ -952,8 +957,8 @@ struct aws_http_message *aws_http2_message_new_from_http1( 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) + * 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); @@ -970,7 +975,8 @@ struct aws_http_message *aws_http2_message_new_from_http1( (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 + /* 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; @@ -1107,6 +1113,15 @@ int aws_http_stream_send_response(struct aws_http_stream *stream, struct aws_htt return stream->owning_connection->vtable->stream_send_response(stream, response); } +struct aws_http_stream *aws_http_stream_acquire(struct aws_http_stream *stream) { + AWS_PRECONDITION(stream); + + size_t prev_refcount = aws_atomic_fetch_add(&stream->refcount, 1); + AWS_LOGF_TRACE( + AWS_LS_HTTP_STREAM, "id=%p: Stream refcount acquired, %zu remaining.", (void *)stream, prev_refcount + 1); + return stream; +} + void aws_http_stream_release(struct aws_http_stream *stream) { if (!stream) { return; @@ -1186,6 +1201,10 @@ uint32_t aws_http_stream_get_id(const struct aws_http_stream *stream) { return stream->id; } +void aws_http_stream_cancel(struct aws_http_stream *stream, int error_code) { + stream->vtable->cancel(stream, error_code); +} + int aws_http2_stream_reset(struct aws_http_stream *http2_stream, uint32_t http2_error) { AWS_PRECONDITION(http2_stream); AWS_PRECONDITION(http2_stream->vtable); diff --git a/contrib/restricted/aws/aws-c-http/source/websocket_bootstrap.c b/contrib/restricted/aws/aws-c-http/source/websocket_bootstrap.c index b5225873059..6c66c8515c5 100644 --- a/contrib/restricted/aws/aws-c-http/source/websocket_bootstrap.c +++ b/contrib/restricted/aws/aws-c-http/source/websocket_bootstrap.c @@ -215,6 +215,7 @@ int aws_websocket_client_connect(const struct aws_websocket_client_connection_op http_options.on_setup = s_ws_bootstrap_on_http_setup; http_options.on_shutdown = s_ws_bootstrap_on_http_shutdown; http_options.requested_event_loop = options->requested_event_loop; + http_options.host_resolution_config = options->host_resolution_config; /* Infer port, if not explicitly specified in URI */ http_options.port = options->port; @@ -234,7 +235,7 @@ int aws_websocket_client_connect(const struct aws_websocket_client_connection_op /* Success! (so far) */ AWS_LOGF_TRACE( AWS_LS_HTTP_WEBSOCKET_SETUP, - "id=%p: Websocket setup begun, connecting to " PRInSTR ":%" PRIu16 PRInSTR, + "id=%p: Websocket setup begun, connecting to " PRInSTR ":%" PRIu32 PRInSTR, (void *)ws_bootstrap, AWS_BYTE_CURSOR_PRI(options->host), options->port, diff --git a/contrib/restricted/aws/aws-c-http/ya.make b/contrib/restricted/aws/aws-c-http/ya.make index 641db7b8269..25cf51985e2 100644 --- a/contrib/restricted/aws/aws-c-http/ya.make +++ b/contrib/restricted/aws/aws-c-http/ya.make @@ -6,9 +6,9 @@ LICENSE(Apache-2.0) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(0.7.6) +VERSION(0.8.1) -ORIGINAL_SOURCE(https://github.com/awslabs/aws-c-http/archive/v0.7.6.tar.gz) +ORIGINAL_SOURCE(https://github.com/awslabs/aws-c-http/archive/v0.8.1.tar.gz) PEERDIR( contrib/restricted/aws/aws-c-cal |
