Skip to content

Commit de1ed16

Browse files
authored
Manager proxy (#127)
* connection manager proxy configuration * websocket proxy configuration
1 parent b01f3b3 commit de1ed16

8 files changed

+231
-36
lines changed

include/aws/http/connection_manager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
struct aws_client_bootstrap;
2424
struct aws_http_connection;
2525
struct aws_http_connection_manager;
26-
struct aws_http_connection_manager_mocks;
2726
struct aws_socket_options;
2827
struct aws_tls_connection_options;
2928

@@ -46,6 +45,7 @@ struct aws_http_connection_manager_options {
4645
size_t initial_window_size;
4746
struct aws_socket_options *socket_options;
4847
struct aws_tls_connection_options *tls_connection_options;
48+
struct aws_http_proxy_options *proxy_options;
4949
struct aws_byte_cursor host;
5050
uint16_t port;
5151

include/aws/http/private/proxy_impl.h

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@ enum aws_proxy_bootstrap_state {
4040
AWS_PBS_FAILURE,
4141
};
4242

43+
/**
44+
* A persistent copy of the aws_http_proxy_options struct. Clones everything appropriate.
45+
*/
46+
struct aws_http_proxy_config {
47+
48+
struct aws_allocator *allocator;
49+
50+
struct aws_byte_buf host;
51+
52+
uint16_t port;
53+
54+
struct aws_tls_connection_options *tls_options;
55+
56+
enum aws_http_proxy_authentication_type auth_type;
57+
58+
struct aws_byte_buf auth_username;
59+
60+
struct aws_byte_buf auth_password;
61+
};
62+
4363
/*
4464
* When a proxy connection is made, we wrap the user-supplied user data with this
4565
* proxy user data. Callbacks are passed properly to the user. By having this data
@@ -65,9 +85,7 @@ struct aws_http_proxy_user_data {
6585

6686
struct aws_tls_connection_options *tls_options;
6787

68-
enum aws_http_proxy_authentication_type auth_type;
69-
struct aws_string *username;
70-
struct aws_string *password;
88+
struct aws_http_proxy_config *proxy_config;
7189
};
7290

7391
struct aws_http_proxy_system_vtable {
@@ -95,6 +113,19 @@ int aws_http_rewrite_uri_for_proxy_request(
95113
AWS_HTTP_API
96114
void aws_http_proxy_system_set_vtable(struct aws_http_proxy_system_vtable *vtable);
97115

116+
AWS_HTTP_API
117+
struct aws_http_proxy_config *aws_http_proxy_config_new(
118+
struct aws_allocator *allocator,
119+
const struct aws_http_proxy_options *options);
120+
121+
AWS_HTTP_API
122+
void aws_http_proxy_config_destroy(struct aws_http_proxy_config *config);
123+
124+
AWS_HTTP_API
125+
void aws_http_proxy_options_init_from_config(
126+
struct aws_http_proxy_options *options,
127+
const struct aws_http_proxy_config *config);
128+
98129
AWS_EXTERN_C_END
99130

100131
#endif /* AWS_HTTP_PROXY_IMPL_H */

include/aws/http/websocket.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ struct aws_websocket_client_connection_options {
158158
*/
159159
struct aws_tls_connection_options *tls_options;
160160

161+
/**
162+
* Optional
163+
* Configuration options related to http proxy usage.
164+
*/
165+
struct aws_http_proxy_options *proxy_options;
166+
161167
/**
162168
* Required.
163169
* aws_websocket_client_connect() makes a copy.

source/connection_manager.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <aws/http/connection.h>
2323
#include <aws/http/private/connection_manager_system_vtable.h>
2424
#include <aws/http/private/http_impl.h>
25+
#include <aws/http/private/proxy_impl.h>
2526
#include <aws/io/channel_bootstrap.h>
2627
#include <aws/io/logging.h>
2728
#include <aws/io/socket.h>
@@ -169,6 +170,7 @@ struct aws_http_connection_manager {
169170
size_t initial_window_size;
170171
struct aws_socket_options socket_options;
171172
struct aws_tls_connection_options *tls_connection_options;
173+
struct aws_http_proxy_config *proxy_config;
172174
struct aws_string *host;
173175
uint16_t port;
174176

@@ -494,6 +496,10 @@ static void s_aws_http_connection_manager_destroy(struct aws_http_connection_man
494496
aws_mem_release(manager->allocator, manager->tls_connection_options);
495497
}
496498

499+
if (manager->proxy_config) {
500+
aws_http_proxy_config_destroy(manager->proxy_config);
501+
}
502+
497503
aws_mutex_clean_up(&manager->lock);
498504

499505
aws_mem_release(manager->allocator, manager);
@@ -536,13 +542,19 @@ struct aws_http_connection_manager *aws_http_connection_manager_new(
536542
}
537543

538544
if (options->tls_connection_options) {
539-
manager->tls_connection_options = aws_mem_acquire(allocator, sizeof(struct aws_tls_connection_options));
540-
AWS_ZERO_STRUCT(*manager->tls_connection_options);
545+
manager->tls_connection_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
541546
if (aws_tls_connection_options_copy(manager->tls_connection_options, options->tls_connection_options)) {
542547
goto on_error;
543548
}
544549
}
545550

551+
if (options->proxy_options) {
552+
manager->proxy_config = aws_http_proxy_config_new(allocator, options->proxy_options);
553+
if (manager->proxy_config == NULL) {
554+
goto on_error;
555+
}
556+
}
557+
546558
manager->state = AWS_HCMST_READY;
547559
manager->initial_window_size = options->initial_window_size;
548560
manager->port = options->port;
@@ -626,6 +638,14 @@ static int s_aws_http_connection_manager_new_connection(struct aws_http_connecti
626638
options.on_setup = s_aws_http_connection_manager_on_connection_setup;
627639
options.on_shutdown = s_aws_http_connection_manager_on_connection_shutdown;
628640

641+
struct aws_http_proxy_options proxy_options;
642+
AWS_ZERO_STRUCT(proxy_options);
643+
644+
if (manager->proxy_config) {
645+
aws_http_proxy_options_init_from_config(&proxy_options, manager->proxy_config);
646+
options.proxy_options = &proxy_options;
647+
}
648+
629649
if (manager->system_vtable->create_connection(&options)) {
630650
AWS_LOGF_ERROR(
631651
AWS_LS_HTTP_CONNECTION_MANAGER,

source/proxy_connection.c

Lines changed: 86 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ void aws_http_proxy_user_data_destroy(struct aws_http_proxy_user_data *user_data
5353
}
5454

5555
aws_string_destroy(user_data->original_host);
56-
aws_string_destroy(user_data->username);
57-
aws_string_destroy(user_data->password);
56+
if (user_data->proxy_config) {
57+
aws_http_proxy_config_destroy(user_data->proxy_config);
58+
}
5859

5960
if (user_data->tls_options) {
6061
aws_tls_connection_options_clean_up(user_data->tls_options);
@@ -68,6 +69,8 @@ struct aws_http_proxy_user_data *aws_http_proxy_user_data_new(
6869
struct aws_allocator *allocator,
6970
const struct aws_http_client_connection_options *options) {
7071

72+
AWS_FATAL_ASSERT(options->proxy_options != NULL);
73+
7174
struct aws_http_proxy_user_data *user_data = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_user_data));
7275
if (user_data == NULL) {
7376
return NULL;
@@ -83,19 +86,10 @@ struct aws_http_proxy_user_data *aws_http_proxy_user_data_new(
8386
}
8487

8588
user_data->original_port = options->port;
86-
user_data->auth_type = options->proxy_options->auth_type;
87-
if (user_data->auth_type == AWS_HPAT_BASIC) {
88-
const struct aws_byte_cursor *user_name = &options->proxy_options->auth_username;
89-
user_data->username = aws_string_new_from_array(allocator, user_name->ptr, user_name->len);
90-
if (user_data->username == NULL) {
91-
goto on_error;
92-
}
9389

94-
const struct aws_byte_cursor *password = &options->proxy_options->auth_password;
95-
user_data->password = aws_string_new_from_array(allocator, password->ptr, password->len);
96-
if (user_data->password == NULL) {
97-
goto on_error;
98-
}
90+
user_data->proxy_config = aws_http_proxy_config_new(allocator, options->proxy_options);
91+
if (user_data->proxy_config == NULL) {
92+
goto on_error;
9993
}
10094

10195
if (options->tls_options) {
@@ -146,12 +140,12 @@ static int s_add_basic_proxy_authentication_header(
146140
if (aws_byte_buf_init(
147141
&base64_input_value,
148142
proxy_user_data->allocator,
149-
proxy_user_data->username->len + proxy_user_data->password->len + 1)) {
143+
proxy_user_data->proxy_config->auth_username.len + proxy_user_data->proxy_config->auth_password.len + 1)) {
150144
goto done;
151145
}
152146

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

164-
struct aws_byte_cursor password_cursor = aws_byte_cursor_from_string(proxy_user_data->password);
158+
struct aws_byte_cursor password_cursor = aws_byte_cursor_from_buf(&proxy_user_data->proxy_config->auth_password);
165159
if (aws_byte_buf_append(&base64_input_value, &password_cursor)) {
166160
goto done;
167161
}
@@ -345,7 +339,8 @@ static struct aws_http_message *s_build_proxy_connect_request(struct aws_http_pr
345339
goto on_error;
346340
}
347341

348-
if (user_data->auth_type == AWS_HPAT_BASIC && s_add_basic_proxy_authentication_header(request, user_data)) {
342+
if (user_data->proxy_config->auth_type == AWS_HPAT_BASIC &&
343+
s_add_basic_proxy_authentication_header(request, user_data)) {
349344
goto on_error;
350345
}
351346

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

673668
int result = AWS_OP_ERR;
674669

675-
if (proxy_ud->auth_type == AWS_HPAT_BASIC && s_add_basic_proxy_authentication_header(request, proxy_ud)) {
670+
if (proxy_ud->proxy_config->auth_type == AWS_HPAT_BASIC &&
671+
s_add_basic_proxy_authentication_header(request, proxy_ud)) {
676672
goto done;
677673
}
678674

@@ -791,3 +787,74 @@ int aws_http_client_connect_via_proxy(const struct aws_http_client_connection_op
791787
return s_aws_http_client_connect_via_proxy_http(options);
792788
}
793789
}
790+
791+
struct aws_http_proxy_config *aws_http_proxy_config_new(
792+
struct aws_allocator *allocator,
793+
const struct aws_http_proxy_options *options) {
794+
AWS_FATAL_ASSERT(options != NULL);
795+
struct aws_http_proxy_config *config = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_config));
796+
if (config == NULL) {
797+
return NULL;
798+
}
799+
800+
if (aws_byte_buf_init_copy_from_cursor(&config->host, allocator, options->host)) {
801+
goto on_error;
802+
}
803+
804+
if (aws_byte_buf_init_copy_from_cursor(&config->auth_username, allocator, options->auth_username)) {
805+
goto on_error;
806+
}
807+
808+
if (aws_byte_buf_init_copy_from_cursor(&config->auth_password, allocator, options->auth_password)) {
809+
goto on_error;
810+
}
811+
812+
if (options->tls_options) {
813+
config->tls_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
814+
if (aws_tls_connection_options_copy(config->tls_options, options->tls_options)) {
815+
goto on_error;
816+
}
817+
}
818+
819+
config->allocator = allocator;
820+
config->auth_type = options->auth_type;
821+
config->port = options->port;
822+
823+
return config;
824+
825+
on_error:
826+
827+
aws_http_proxy_config_destroy(config);
828+
829+
return NULL;
830+
}
831+
832+
void aws_http_proxy_config_destroy(struct aws_http_proxy_config *config) {
833+
if (config == NULL) {
834+
return;
835+
}
836+
837+
aws_byte_buf_clean_up(&config->host);
838+
aws_byte_buf_clean_up(&config->auth_username);
839+
aws_byte_buf_clean_up(&config->auth_password);
840+
841+
if (config->tls_options) {
842+
aws_tls_connection_options_clean_up(config->tls_options);
843+
aws_mem_release(config->allocator, config->tls_options);
844+
}
845+
846+
aws_mem_release(config->allocator, config);
847+
}
848+
849+
void aws_http_proxy_options_init_from_config(
850+
struct aws_http_proxy_options *options,
851+
const struct aws_http_proxy_config *config) {
852+
AWS_FATAL_ASSERT(options && config);
853+
854+
options->host = aws_byte_cursor_from_buf(&config->host);
855+
options->auth_username = aws_byte_cursor_from_buf(&config->auth_username);
856+
options->auth_password = aws_byte_cursor_from_buf(&config->auth_password);
857+
options->auth_type = config->auth_type;
858+
options->port = config->port;
859+
options->tls_options = config->tls_options;
860+
}

source/websocket_bootstrap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ int aws_websocket_client_connect(const struct aws_websocket_client_connection_op
191191
http_options.host_name = options->host;
192192
http_options.socket_options = options->socket_options;
193193
http_options.tls_options = options->tls_options;
194+
http_options.proxy_options = options->proxy_options;
194195
http_options.initial_window_size = 1024; /* Adequate space for response data to trickle in */
195196
http_options.user_data = ws_bootstrap;
196197
http_options.on_setup = s_ws_bootstrap_on_http_setup;

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ add_test_case(test_connection_manager_acquire_release_mix_synchronous)
191191
add_test_case(test_connection_manager_connect_callback_failure)
192192
add_test_case(test_connection_manager_connect_immediate_failure)
193193
add_test_case(test_connection_manager_success_then_cancel_pending_from_failure)
194+
add_test_case(test_connection_manager_proxy_setup_shutdown)
195+
add_test_case(test_connection_manager_proxy_acquire_single)
194196

195197
add_test_case(h1_server_sanity_check)
196198
add_test_case(h1_server_receive_1line_request)

0 commit comments

Comments
 (0)