Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/aws/http/connection_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
struct aws_client_bootstrap;
struct aws_http_connection;
struct aws_http_connection_manager;
struct aws_http_connection_manager_mocks;
struct aws_socket_options;
struct aws_tls_connection_options;

Expand All @@ -46,6 +45,7 @@ struct aws_http_connection_manager_options {
size_t initial_window_size;
struct aws_socket_options *socket_options;
struct aws_tls_connection_options *tls_connection_options;
struct aws_http_proxy_options *proxy_options;
struct aws_byte_cursor host;
uint16_t port;

Expand Down
37 changes: 34 additions & 3 deletions include/aws/http/private/proxy_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ enum aws_proxy_bootstrap_state {
AWS_PBS_FAILURE,
};

/**
* A persistent copy of the aws_http_proxy_options struct. Clones everything appropriate.
*/
struct aws_http_proxy_config {

struct aws_allocator *allocator;

struct aws_byte_buf host;

uint16_t port;

struct aws_tls_connection_options *tls_options;

enum aws_http_proxy_authentication_type auth_type;

struct aws_byte_buf auth_username;

struct aws_byte_buf auth_password;
};

/*
* When a proxy connection is made, we wrap the user-supplied user data with this
* proxy user data. Callbacks are passed properly to the user. By having this data
Expand All @@ -65,9 +85,7 @@ struct aws_http_proxy_user_data {

struct aws_tls_connection_options *tls_options;

enum aws_http_proxy_authentication_type auth_type;
struct aws_string *username;
struct aws_string *password;
struct aws_http_proxy_config *proxy_config;
};

struct aws_http_proxy_system_vtable {
Expand Down Expand Up @@ -95,6 +113,19 @@ int aws_http_rewrite_uri_for_proxy_request(
AWS_HTTP_API
void aws_http_proxy_system_set_vtable(struct aws_http_proxy_system_vtable *vtable);

AWS_HTTP_API
struct aws_http_proxy_config *aws_http_proxy_config_new(
struct aws_allocator *allocator,
const struct aws_http_proxy_options *options);

AWS_HTTP_API
void aws_http_proxy_config_destroy(struct aws_http_proxy_config *config);

AWS_HTTP_API
void aws_http_proxy_options_init_from_config(
struct aws_http_proxy_options *options,
const struct aws_http_proxy_config *config);

AWS_EXTERN_C_END

#endif /* AWS_HTTP_PROXY_IMPL_H */
6 changes: 6 additions & 0 deletions include/aws/http/websocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ struct aws_websocket_client_connection_options {
*/
struct aws_tls_connection_options *tls_options;

/**
* Optional
* Configuration options related to http proxy usage.
*/
struct aws_http_proxy_options *proxy_options;

/**
* Required.
* aws_websocket_client_connect() makes a copy.
Expand Down
24 changes: 22 additions & 2 deletions source/connection_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <aws/http/connection.h>
#include <aws/http/private/connection_manager_system_vtable.h>
#include <aws/http/private/http_impl.h>
#include <aws/http/private/proxy_impl.h>
#include <aws/io/channel_bootstrap.h>
#include <aws/io/logging.h>
#include <aws/io/socket.h>
Expand Down Expand Up @@ -169,6 +170,7 @@ struct aws_http_connection_manager {
size_t initial_window_size;
struct aws_socket_options socket_options;
struct aws_tls_connection_options *tls_connection_options;
struct aws_http_proxy_config *proxy_config;
struct aws_string *host;
uint16_t port;

Expand Down Expand Up @@ -494,6 +496,10 @@ static void s_aws_http_connection_manager_destroy(struct aws_http_connection_man
aws_mem_release(manager->allocator, manager->tls_connection_options);
}

if (manager->proxy_config) {
aws_http_proxy_config_destroy(manager->proxy_config);
}

aws_mutex_clean_up(&manager->lock);

aws_mem_release(manager->allocator, manager);
Expand Down Expand Up @@ -536,13 +542,19 @@ struct aws_http_connection_manager *aws_http_connection_manager_new(
}

if (options->tls_connection_options) {
manager->tls_connection_options = aws_mem_acquire(allocator, sizeof(struct aws_tls_connection_options));
AWS_ZERO_STRUCT(*manager->tls_connection_options);
manager->tls_connection_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
if (aws_tls_connection_options_copy(manager->tls_connection_options, options->tls_connection_options)) {
goto on_error;
}
}

if (options->proxy_options) {
manager->proxy_config = aws_http_proxy_config_new(allocator, options->proxy_options);
if (manager->proxy_config == NULL) {
goto on_error;
}
}

manager->state = AWS_HCMST_READY;
manager->initial_window_size = options->initial_window_size;
manager->port = options->port;
Expand Down Expand Up @@ -626,6 +638,14 @@ static int s_aws_http_connection_manager_new_connection(struct aws_http_connecti
options.on_setup = s_aws_http_connection_manager_on_connection_setup;
options.on_shutdown = s_aws_http_connection_manager_on_connection_shutdown;

struct aws_http_proxy_options proxy_options;
AWS_ZERO_STRUCT(proxy_options);

if (manager->proxy_config) {
aws_http_proxy_options_init_from_config(&proxy_options, manager->proxy_config);
options.proxy_options = &proxy_options;
}

if (manager->system_vtable->create_connection(&options)) {
AWS_LOGF_ERROR(
AWS_LS_HTTP_CONNECTION_MANAGER,
Expand Down
105 changes: 86 additions & 19 deletions source/proxy_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ void aws_http_proxy_user_data_destroy(struct aws_http_proxy_user_data *user_data
}

aws_string_destroy(user_data->original_host);
aws_string_destroy(user_data->username);
aws_string_destroy(user_data->password);
if (user_data->proxy_config) {
aws_http_proxy_config_destroy(user_data->proxy_config);
}

if (user_data->tls_options) {
aws_tls_connection_options_clean_up(user_data->tls_options);
Expand All @@ -68,6 +69,8 @@ struct aws_http_proxy_user_data *aws_http_proxy_user_data_new(
struct aws_allocator *allocator,
const struct aws_http_client_connection_options *options) {

AWS_FATAL_ASSERT(options->proxy_options != NULL);

struct aws_http_proxy_user_data *user_data = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_user_data));
if (user_data == NULL) {
return NULL;
Expand All @@ -83,19 +86,10 @@ struct aws_http_proxy_user_data *aws_http_proxy_user_data_new(
}

user_data->original_port = options->port;
user_data->auth_type = options->proxy_options->auth_type;
if (user_data->auth_type == AWS_HPAT_BASIC) {
const struct aws_byte_cursor *user_name = &options->proxy_options->auth_username;
user_data->username = aws_string_new_from_array(allocator, user_name->ptr, user_name->len);
if (user_data->username == NULL) {
goto on_error;
}

const struct aws_byte_cursor *password = &options->proxy_options->auth_password;
user_data->password = aws_string_new_from_array(allocator, password->ptr, password->len);
if (user_data->password == NULL) {
goto on_error;
}
user_data->proxy_config = aws_http_proxy_config_new(allocator, options->proxy_options);
if (user_data->proxy_config == NULL) {
goto on_error;
}

if (options->tls_options) {
Expand Down Expand Up @@ -146,12 +140,12 @@ static int s_add_basic_proxy_authentication_header(
if (aws_byte_buf_init(
&base64_input_value,
proxy_user_data->allocator,
proxy_user_data->username->len + proxy_user_data->password->len + 1)) {
proxy_user_data->proxy_config->auth_username.len + proxy_user_data->proxy_config->auth_password.len + 1)) {
goto done;
}

/* First build a buffer with "username:password" in it */
struct aws_byte_cursor username_cursor = aws_byte_cursor_from_string(proxy_user_data->username);
struct aws_byte_cursor username_cursor = aws_byte_cursor_from_buf(&proxy_user_data->proxy_config->auth_username);
if (aws_byte_buf_append(&base64_input_value, &username_cursor)) {
goto done;
}
Expand All @@ -161,7 +155,7 @@ static int s_add_basic_proxy_authentication_header(
goto done;
}

struct aws_byte_cursor password_cursor = aws_byte_cursor_from_string(proxy_user_data->password);
struct aws_byte_cursor password_cursor = aws_byte_cursor_from_buf(&proxy_user_data->proxy_config->auth_password);
if (aws_byte_buf_append(&base64_input_value, &password_cursor)) {
goto done;
}
Expand Down Expand Up @@ -345,7 +339,8 @@ static struct aws_http_message *s_build_proxy_connect_request(struct aws_http_pr
goto on_error;
}

if (user_data->auth_type == AWS_HPAT_BASIC && s_add_basic_proxy_authentication_header(request, user_data)) {
if (user_data->proxy_config->auth_type == AWS_HPAT_BASIC &&
s_add_basic_proxy_authentication_header(request, user_data)) {
goto on_error;
}

Expand Down Expand Up @@ -672,7 +667,8 @@ static int s_proxy_http_request_transform(struct aws_http_message *request, void

int result = AWS_OP_ERR;

if (proxy_ud->auth_type == AWS_HPAT_BASIC && s_add_basic_proxy_authentication_header(request, proxy_ud)) {
if (proxy_ud->proxy_config->auth_type == AWS_HPAT_BASIC &&
s_add_basic_proxy_authentication_header(request, proxy_ud)) {
goto done;
}

Expand Down Expand Up @@ -791,3 +787,74 @@ int aws_http_client_connect_via_proxy(const struct aws_http_client_connection_op
return s_aws_http_client_connect_via_proxy_http(options);
}
}

struct aws_http_proxy_config *aws_http_proxy_config_new(
struct aws_allocator *allocator,
const struct aws_http_proxy_options *options) {
AWS_FATAL_ASSERT(options != NULL);
struct aws_http_proxy_config *config = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_config));
if (config == NULL) {
return NULL;
}

if (aws_byte_buf_init_copy_from_cursor(&config->host, allocator, options->host)) {
goto on_error;
}

if (aws_byte_buf_init_copy_from_cursor(&config->auth_username, allocator, options->auth_username)) {
goto on_error;
}

if (aws_byte_buf_init_copy_from_cursor(&config->auth_password, allocator, options->auth_password)) {
goto on_error;
}

if (options->tls_options) {
config->tls_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
if (aws_tls_connection_options_copy(config->tls_options, options->tls_options)) {
goto on_error;
}
}

config->allocator = allocator;
config->auth_type = options->auth_type;
config->port = options->port;

return config;

on_error:

aws_http_proxy_config_destroy(config);

return NULL;
}

void aws_http_proxy_config_destroy(struct aws_http_proxy_config *config) {
if (config == NULL) {
return;
}

aws_byte_buf_clean_up(&config->host);
aws_byte_buf_clean_up(&config->auth_username);
aws_byte_buf_clean_up(&config->auth_password);

if (config->tls_options) {
aws_tls_connection_options_clean_up(config->tls_options);
aws_mem_release(config->allocator, config->tls_options);
}

aws_mem_release(config->allocator, config);
}

void aws_http_proxy_options_init_from_config(
struct aws_http_proxy_options *options,
const struct aws_http_proxy_config *config) {
AWS_FATAL_ASSERT(options && config);

options->host = aws_byte_cursor_from_buf(&config->host);
options->auth_username = aws_byte_cursor_from_buf(&config->auth_username);
options->auth_password = aws_byte_cursor_from_buf(&config->auth_password);
options->auth_type = config->auth_type;
options->port = config->port;
options->tls_options = config->tls_options;
}
1 change: 1 addition & 0 deletions source/websocket_bootstrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ int aws_websocket_client_connect(const struct aws_websocket_client_connection_op
http_options.host_name = options->host;
http_options.socket_options = options->socket_options;
http_options.tls_options = options->tls_options;
http_options.proxy_options = options->proxy_options;
http_options.initial_window_size = 1024; /* Adequate space for response data to trickle in */
http_options.user_data = ws_bootstrap;
http_options.on_setup = s_ws_bootstrap_on_http_setup;
Expand Down
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ add_test_case(test_connection_manager_acquire_release_mix_synchronous)
add_test_case(test_connection_manager_connect_callback_failure)
add_test_case(test_connection_manager_connect_immediate_failure)
add_test_case(test_connection_manager_success_then_cancel_pending_from_failure)
add_test_case(test_connection_manager_proxy_setup_shutdown)
add_test_case(test_connection_manager_proxy_acquire_single)

add_test_case(h1_server_sanity_check)
add_test_case(h1_server_receive_1line_request)
Expand Down
Loading