1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include <aws/http/connection.h>
7 #include <aws/http/private/connection_impl.h>
8 #include <aws/http/server.h>
9
10 #include <aws/common/clock.h>
11 #include <aws/common/condition_variable.h>
12 #include <aws/common/log_writer.h>
13 #include <aws/common/string.h>
14 #include <aws/common/thread.h>
15 #include <aws/common/uuid.h>
16 #include <aws/io/channel_bootstrap.h>
17 #include <aws/io/event_loop.h>
18 #include <aws/io/logging.h>
19 #include <aws/io/socket.h>
20 #include <aws/io/tls_channel_handler.h>
21 #include <aws/testing/aws_test_harness.h>
22
23 #if _MSC_VER
24 # pragma warning(disable : 4204) /* non-constant aggregate initializer */
25 #endif
26
27 #ifdef _WIN32
28 # define LOCAL_SOCK_TEST_FORMAT "\\\\.\\pipe\\testsock-%s"
29 #else
30 # define LOCAL_SOCK_TEST_FORMAT "testsock-%s.sock"
31 #endif
32
33 enum {
34 TESTER_TIMEOUT_SEC = 60, /* Give enough time for non-sudo users to enter password */
35 };
36
37 /* Options for setting up `tester` singleton */
38 struct tester_options {
39 struct aws_allocator *alloc;
40 bool tls;
41 char *server_alpn_list;
42 char *client_alpn_list;
43 bool no_connection; /* don't connect server to client */
44 };
45
46 /* Singleton used by tests in this file */
47 struct tester {
48 struct aws_allocator *alloc;
49 struct aws_event_loop_group *event_loop_group;
50 struct aws_host_resolver *host_resolver;
51 struct aws_server_bootstrap *server_bootstrap;
52 struct aws_http_server *server;
53 struct aws_client_bootstrap *client_bootstrap;
54 struct aws_http_client_connection_options client_options;
55
56 int server_connection_num;
57 int client_connection_num;
58 int wait_server_connection_num;
59 int wait_client_connection_num;
60 struct aws_http_connection *server_connections[10];
61 struct aws_http_connection *client_connections[10];
62
63 struct aws_socket_endpoint endpoint;
64 struct aws_socket_options socket_options;
65
66 int client_connection_is_shutdown;
67 int server_connection_is_shutdown;
68 int wait_client_connection_is_shutdown;
69 int wait_server_connection_is_shutdown;
70
71 bool server_is_shutdown;
72 struct aws_http_connection *new_client_connection;
73 bool new_client_shut_down;
74 bool new_client_setup_finished;
75
76 enum aws_http_version connection_version;
77
78 /* Tls context */
79 struct aws_tls_ctx_options server_ctx_options;
80 struct aws_tls_ctx_options client_ctx_options;
81 struct aws_tls_ctx *server_ctx;
82 struct aws_tls_ctx *client_ctx;
83 struct aws_tls_connection_options server_tls_connection_options;
84 struct aws_tls_connection_options client_tls_connection_options;
85 struct aws_byte_buf negotiated_protocol;
86
87 /* If we need to wait for some async process*/
88 struct aws_mutex wait_lock;
89 struct aws_condition_variable wait_cvar;
90 /* we need wait result for both server side and client side */
91 int server_wait_result;
92 int client_wait_result;
93 };
94
s_tester_on_incoming_request(struct aws_http_connection * connection,void * user_data)95 static struct aws_http_stream *s_tester_on_incoming_request(struct aws_http_connection *connection, void *user_data) {
96 (void)connection;
97 (void)user_data;
98 aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
99 return NULL;
100 }
101
s_tester_http_server_on_destroy(void * user_data)102 static void s_tester_http_server_on_destroy(void *user_data) {
103 struct tester *tester = user_data;
104 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
105 tester->server_is_shutdown = true;
106 tester->server = NULL;
107 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
108 aws_condition_variable_notify_one(&tester->wait_cvar);
109 }
110
s_tester_on_server_connection_shutdown(struct aws_http_connection * connection,int error_code,void * user_data)111 static void s_tester_on_server_connection_shutdown(
112 struct aws_http_connection *connection,
113 int error_code,
114 void *user_data) {
115
116 (void)connection;
117 (void)error_code;
118 struct tester *tester = user_data;
119 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
120
121 tester->server_connection_is_shutdown++;
122
123 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
124 aws_condition_variable_notify_one(&tester->wait_cvar);
125 }
126
s_tester_on_server_connection_setup(struct aws_http_server * server,struct aws_http_connection * connection,int error_code,void * user_data)127 static void s_tester_on_server_connection_setup(
128 struct aws_http_server *server,
129 struct aws_http_connection *connection,
130 int error_code,
131 void *user_data) {
132
133 (void)server;
134 struct tester *tester = user_data;
135 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
136
137 if (error_code) {
138 tester->server_wait_result = error_code;
139 goto done;
140 }
141
142 struct aws_http_server_connection_options options = AWS_HTTP_SERVER_CONNECTION_OPTIONS_INIT;
143 options.connection_user_data = tester;
144 options.on_incoming_request = s_tester_on_incoming_request;
145 options.on_shutdown = s_tester_on_server_connection_shutdown;
146
147 int err = aws_http_connection_configure_server(connection, &options);
148 if (err) {
149 tester->server_wait_result = aws_last_error();
150 goto done;
151 }
152
153 tester->server_connections[tester->server_connection_num++] = connection;
154 done:
155 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
156 aws_condition_variable_notify_one(&tester->wait_cvar);
157 }
158
s_tester_on_client_connection_setup(struct aws_http_connection * connection,int error_code,void * user_data)159 static void s_tester_on_client_connection_setup(
160 struct aws_http_connection *connection,
161 int error_code,
162 void *user_data) {
163
164 struct tester *tester = user_data;
165 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
166
167 if (error_code) {
168 tester->client_wait_result = error_code;
169 goto done;
170 }
171 tester->connection_version = aws_http_connection_get_version(connection);
172 tester->client_connections[tester->client_connection_num++] = connection;
173 done:
174 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
175 aws_condition_variable_notify_one(&tester->wait_cvar);
176 }
177
s_tester_on_client_connection_shutdown(struct aws_http_connection * connection,int error_code,void * user_data)178 static void s_tester_on_client_connection_shutdown(
179 struct aws_http_connection *connection,
180 int error_code,
181 void *user_data) {
182
183 (void)connection;
184 (void)error_code;
185 struct tester *tester = user_data;
186 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
187
188 tester->client_connection_is_shutdown++;
189
190 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
191 aws_condition_variable_notify_one(&tester->wait_cvar);
192 }
193
s_tester_wait(struct tester * tester,bool (* pred)(void * user_data))194 static int s_tester_wait(struct tester *tester, bool (*pred)(void *user_data)) {
195 int local_wait_result;
196 ASSERT_SUCCESS(aws_mutex_lock(&tester->wait_lock));
197 int err = aws_condition_variable_wait_for_pred(
198 &tester->wait_cvar,
199 &tester->wait_lock,
200 aws_timestamp_convert(TESTER_TIMEOUT_SEC, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_NANOS, NULL),
201 pred,
202 tester);
203 if (tester->server_wait_result) {
204 local_wait_result = tester->server_wait_result;
205 } else {
206 local_wait_result = tester->client_wait_result;
207 }
208 tester->server_wait_result = 0;
209 tester->client_wait_result = 0;
210 ASSERT_SUCCESS(aws_mutex_unlock(&tester->wait_lock));
211 ASSERT_SUCCESS(err);
212 if (local_wait_result) {
213 return aws_raise_error(local_wait_result);
214 }
215 return AWS_OP_SUCCESS;
216 }
217
s_tester_connection_setup_pred(void * user_data)218 static bool s_tester_connection_setup_pred(void *user_data) {
219 struct tester *tester = user_data;
220 return (tester->server_wait_result || tester->client_wait_result) ||
221 (tester->client_connection_num == tester->wait_client_connection_num &&
222 tester->server_connection_num == tester->wait_server_connection_num);
223 }
224
s_tester_connection_shutdown_pred(void * user_data)225 static bool s_tester_connection_shutdown_pred(void *user_data) {
226 struct tester *tester = user_data;
227 return (tester->server_wait_result || tester->client_wait_result) ||
228 (tester->client_connection_is_shutdown == tester->wait_client_connection_is_shutdown &&
229 tester->server_connection_is_shutdown == tester->wait_server_connection_is_shutdown);
230 }
231
s_tester_server_shutdown_pred(void * user_data)232 static bool s_tester_server_shutdown_pred(void *user_data) {
233 struct tester *tester = user_data;
234 return tester->server_is_shutdown;
235 }
236
s_client_connection_options_init_tester(struct aws_http_client_connection_options * client_options,struct tester * tester)237 static void s_client_connection_options_init_tester(
238 struct aws_http_client_connection_options *client_options,
239 struct tester *tester) {
240 struct aws_client_bootstrap_options bootstrap_options = {
241 .event_loop_group = tester->event_loop_group,
242 .host_resolver = tester->host_resolver,
243 };
244 tester->client_bootstrap = aws_client_bootstrap_new(tester->alloc, &bootstrap_options);
245 AWS_FATAL_ASSERT(tester->client_bootstrap != NULL);
246 client_options->allocator = tester->alloc;
247 client_options->bootstrap = tester->client_bootstrap;
248 client_options->host_name = aws_byte_cursor_from_c_str(tester->endpoint.address);
249 client_options->port = tester->endpoint.port;
250 client_options->socket_options = &tester->socket_options;
251 client_options->user_data = tester;
252 client_options->on_setup = s_tester_on_client_connection_setup;
253 client_options->on_shutdown = s_tester_on_client_connection_shutdown;
254 }
255
s_tls_client_opt_tester_init(struct tester * tester,const char * alpn_list,struct aws_byte_cursor server_name)256 static int s_tls_client_opt_tester_init(
257 struct tester *tester,
258 const char *alpn_list,
259 struct aws_byte_cursor server_name) {
260
261 aws_tls_ctx_options_init_default_client(&tester->client_ctx_options, tester->alloc);
262 aws_tls_ctx_options_override_default_trust_store_from_path(&tester->client_ctx_options, NULL, "unittests.crt");
263
264 tester->client_ctx = aws_tls_client_ctx_new(tester->alloc, &tester->client_ctx_options);
265 aws_tls_connection_options_init_from_ctx(&tester->client_tls_connection_options, tester->client_ctx);
266 aws_tls_connection_options_set_alpn_list(&tester->client_tls_connection_options, tester->alloc, alpn_list);
267
268 aws_tls_connection_options_set_server_name(&tester->client_tls_connection_options, tester->alloc, &server_name);
269
270 return AWS_OP_SUCCESS;
271 }
272
s_tls_server_opt_tester_init(struct tester * tester,const char * alpn_list)273 static int s_tls_server_opt_tester_init(struct tester *tester, const char *alpn_list) {
274
275 #ifdef __APPLE__
276 struct aws_byte_cursor pwd_cur = aws_byte_cursor_from_c_str("1234");
277 ASSERT_SUCCESS(aws_tls_ctx_options_init_server_pkcs12_from_path(
278 &tester->server_ctx_options, tester->alloc, "unittests.p12", &pwd_cur));
279 #else
280 ASSERT_SUCCESS(aws_tls_ctx_options_init_default_server_from_path(
281 &tester->server_ctx_options, tester->alloc, "unittests.crt", "unittests.key"));
282 #endif /* __APPLE__ */
283 aws_tls_ctx_options_set_alpn_list(&tester->server_ctx_options, alpn_list);
284 tester->server_ctx = aws_tls_server_ctx_new(tester->alloc, &tester->server_ctx_options);
285 ASSERT_NOT_NULL(tester->server_ctx);
286
287 aws_tls_connection_options_init_from_ctx(&tester->server_tls_connection_options, tester->server_ctx);
288 return AWS_OP_SUCCESS;
289 }
290
s_tester_init(struct tester * tester,const struct tester_options * options)291 static int s_tester_init(struct tester *tester, const struct tester_options *options) {
292 AWS_ZERO_STRUCT(*tester);
293
294 tester->alloc = options->alloc;
295
296 aws_http_library_init(options->alloc);
297 ASSERT_SUCCESS(aws_mutex_init(&tester->wait_lock));
298 ASSERT_SUCCESS(aws_condition_variable_init(&tester->wait_cvar));
299
300 tester->event_loop_group = aws_event_loop_group_new_default(tester->alloc, 1, NULL);
301
302 struct aws_host_resolver_default_options resolver_options = {
303 .el_group = tester->event_loop_group,
304 .max_entries = 8,
305 };
306
307 tester->host_resolver = aws_host_resolver_new_default(tester->alloc, &resolver_options);
308 tester->server_bootstrap = aws_server_bootstrap_new(tester->alloc, tester->event_loop_group);
309 ASSERT_NOT_NULL(tester->server_bootstrap);
310
311 struct aws_socket_options socket_options = {
312 .type = AWS_SOCKET_STREAM,
313 .domain = AWS_SOCKET_LOCAL,
314 .connect_timeout_ms =
315 (uint32_t)aws_timestamp_convert(TESTER_TIMEOUT_SEC, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL),
316 };
317 tester->socket_options = socket_options;
318 /* Generate random address for endpoint */
319 struct aws_uuid uuid;
320 ASSERT_SUCCESS(aws_uuid_init(&uuid));
321 char uuid_str[AWS_UUID_STR_LEN];
322 struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str));
323 ASSERT_SUCCESS(aws_uuid_to_str(&uuid, &uuid_buf));
324 struct aws_socket_endpoint endpoint;
325 AWS_ZERO_STRUCT(endpoint);
326
327 snprintf(endpoint.address, sizeof(endpoint.address), LOCAL_SOCK_TEST_FORMAT, uuid_str);
328 tester->endpoint = endpoint;
329 /* Create server (listening socket) */
330 struct aws_http_server_options server_options = AWS_HTTP_SERVER_OPTIONS_INIT;
331 server_options.allocator = tester->alloc;
332 server_options.bootstrap = tester->server_bootstrap;
333 server_options.endpoint = &tester->endpoint;
334 server_options.socket_options = &tester->socket_options;
335 server_options.server_user_data = tester;
336 server_options.on_incoming_connection = s_tester_on_server_connection_setup;
337 server_options.on_destroy_complete = s_tester_http_server_on_destroy;
338 if (options->tls) {
339 ASSERT_SUCCESS(s_tls_server_opt_tester_init(
340 tester, options->server_alpn_list ? options->server_alpn_list : "h2;http/1.1"));
341 server_options.tls_options = &tester->server_tls_connection_options;
342 }
343
344 tester->server = aws_http_server_new(&server_options);
345 ASSERT_NOT_NULL(tester->server);
346
347 /* If test doesn't need a connection, we're done setting up. */
348 if (options->no_connection) {
349 return AWS_OP_SUCCESS;
350 }
351
352 /* Connect */
353 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
354 s_client_connection_options_init_tester(&client_options, tester);
355 if (options->tls) {
356 ASSERT_SUCCESS(s_tls_client_opt_tester_init(
357 tester,
358 options->client_alpn_list ? options->client_alpn_list : "h2;http/1.1",
359 aws_byte_cursor_from_c_str("localhost")));
360 client_options.tls_options = &tester->client_tls_connection_options;
361 }
362 tester->client_options = client_options;
363
364 tester->server_connection_num = 0;
365 tester->client_connection_num = 0;
366 ASSERT_SUCCESS(aws_http_client_connect(&tester->client_options));
367
368 /* Wait for server & client connections to finish setup */
369 tester->wait_client_connection_num = 1;
370 tester->wait_server_connection_num = 1;
371 ASSERT_SUCCESS(s_tester_wait(tester, s_tester_connection_setup_pred));
372
373 return AWS_OP_SUCCESS;
374 }
375
s_tester_clean_up(struct tester * tester)376 static int s_tester_clean_up(struct tester *tester) {
377 if (tester->server) {
378 /* server is not shut down by test, let's shut down the server here */
379 aws_http_server_release(tester->server);
380 /* wait for the server to finish shutdown process */
381 ASSERT_SUCCESS(s_tester_wait(tester, s_tester_server_shutdown_pred));
382 }
383 if (tester->server_ctx) {
384 aws_tls_connection_options_clean_up(&tester->server_tls_connection_options);
385 aws_tls_ctx_release(tester->server_ctx);
386 aws_tls_ctx_options_clean_up(&tester->server_ctx_options);
387 }
388 if (tester->client_ctx) {
389 aws_tls_connection_options_clean_up(&tester->client_tls_connection_options);
390 aws_tls_ctx_release(tester->client_ctx);
391 aws_tls_ctx_options_clean_up(&tester->client_ctx_options);
392 }
393 aws_byte_buf_clean_up(&tester->negotiated_protocol);
394 aws_server_bootstrap_release(tester->server_bootstrap);
395 aws_client_bootstrap_release(tester->client_bootstrap);
396 aws_host_resolver_release(tester->host_resolver);
397 aws_event_loop_group_release(tester->event_loop_group);
398
399 aws_http_library_clean_up();
400 aws_mutex_clean_up(&tester->wait_lock);
401
402 return AWS_OP_SUCCESS;
403 }
404
s_test_server_new_destroy(struct aws_allocator * allocator,void * ctx)405 static int s_test_server_new_destroy(struct aws_allocator *allocator, void *ctx) {
406 (void)ctx;
407 struct tester_options options = {
408 .alloc = allocator,
409 .no_connection = true,
410 };
411 struct tester tester;
412 ASSERT_SUCCESS(s_tester_init(&tester, &options));
413
414 ASSERT_SUCCESS(s_tester_clean_up(&tester));
415 return AWS_OP_SUCCESS;
416 }
417 AWS_TEST_CASE(server_new_destroy, s_test_server_new_destroy);
418
release_all_client_connections(struct tester * tester)419 void release_all_client_connections(struct tester *tester) {
420 for (int i = 0; i < tester->client_connection_num; i++) {
421 aws_http_connection_release(tester->client_connections[i]);
422 }
423 /* wait for all the connections to shutdown */
424 tester->wait_client_connection_is_shutdown = tester->client_connection_num;
425 }
426
release_all_server_connections(struct tester * tester)427 void release_all_server_connections(struct tester *tester) {
428 for (int i = 0; i < tester->server_connection_num; i++) {
429 aws_http_connection_release(tester->server_connections[i]);
430 }
431 /* wait for all the connections to shutdown */
432 tester->wait_server_connection_is_shutdown = tester->server_connection_num;
433 }
434
s_test_connection_setup_shutdown(struct aws_allocator * allocator,void * ctx)435 static int s_test_connection_setup_shutdown(struct aws_allocator *allocator, void *ctx) {
436 (void)ctx;
437 struct tester_options options = {
438 .alloc = allocator,
439 };
440 struct tester tester;
441 ASSERT_SUCCESS(s_tester_init(&tester, &options));
442
443 release_all_client_connections(&tester);
444 release_all_server_connections(&tester);
445 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
446
447 ASSERT_SUCCESS(s_tester_clean_up(&tester));
448 return AWS_OP_SUCCESS;
449 }
450 AWS_TEST_CASE(connection_setup_shutdown, s_test_connection_setup_shutdown);
451
s_test_connection_setup_shutdown_tls(struct aws_allocator * allocator,void * ctx)452 static int s_test_connection_setup_shutdown_tls(struct aws_allocator *allocator, void *ctx) {
453 (void)ctx;
454
455 #ifdef __APPLE__ /* Something is wrong with APPLE */
456 return AWS_OP_SUCCESS;
457 #endif
458 struct tester_options options = {
459 .alloc = allocator,
460 .tls = true,
461 };
462 struct tester tester;
463 ASSERT_SUCCESS(s_tester_init(&tester, &options));
464
465 release_all_client_connections(&tester);
466 release_all_server_connections(&tester);
467 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
468
469 ASSERT_SUCCESS(s_tester_clean_up(&tester));
470 return AWS_OP_SUCCESS;
471 }
472 AWS_TEST_CASE(connection_setup_shutdown_tls, s_test_connection_setup_shutdown_tls);
473
s_test_connection_setup_shutdown_proxy_setting_on_ev_not_found(struct aws_allocator * allocator,void * ctx)474 static int s_test_connection_setup_shutdown_proxy_setting_on_ev_not_found(struct aws_allocator *allocator, void *ctx) {
475 (void)ctx;
476 struct tester_options options = {
477 .alloc = allocator,
478 .no_connection = true,
479 };
480 struct tester tester;
481 ASSERT_SUCCESS(s_tester_init(&tester, &options));
482 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
483 struct proxy_env_var_settings proxy_ev_settings;
484 AWS_ZERO_STRUCT(proxy_ev_settings);
485 proxy_ev_settings.env_var_type = AWS_HPEV_ENABLE;
486 client_options.proxy_ev_settings = &proxy_ev_settings;
487
488 s_client_connection_options_init_tester(&client_options, &tester);
489 tester.client_options = client_options;
490
491 tester.server_connection_num = 0;
492 tester.client_connection_num = 0;
493 ASSERT_SUCCESS(aws_http_client_connect(&tester.client_options));
494
495 /* Wait for server & client connections to finish setup */
496 tester.wait_client_connection_num = 1;
497 tester.wait_server_connection_num = 1;
498 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_setup_pred));
499
500 release_all_client_connections(&tester);
501 release_all_server_connections(&tester);
502 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
503
504 ASSERT_SUCCESS(s_tester_clean_up(&tester));
505 return AWS_OP_SUCCESS;
506 }
507 AWS_TEST_CASE(
508 connection_setup_shutdown_proxy_setting_on_ev_not_found,
509 s_test_connection_setup_shutdown_proxy_setting_on_ev_not_found);
510
s_test_connection_h2_prior_knowledge(struct aws_allocator * allocator,void * ctx)511 static int s_test_connection_h2_prior_knowledge(struct aws_allocator *allocator, void *ctx) {
512 (void)ctx;
513 struct tester_options options = {
514 .alloc = allocator,
515 .no_connection = true,
516 };
517 struct tester tester;
518 ASSERT_SUCCESS(s_tester_init(&tester, &options));
519
520 /* Connect */
521 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
522 s_client_connection_options_init_tester(&client_options, &tester);
523 client_options.prior_knowledge_http2 = true;
524 tester.client_options = client_options;
525
526 tester.server_connection_num = 0;
527 tester.client_connection_num = 0;
528 ASSERT_SUCCESS(aws_http_client_connect(&tester.client_options));
529
530 /* Wait for server & client connections to finish setup */
531 tester.wait_client_connection_num = 1;
532 tester.wait_server_connection_num = 1;
533 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_setup_pred));
534
535 /* Assert that we made an http2 connection */
536 ASSERT_INT_EQUALS(tester.connection_version, AWS_HTTP_VERSION_2);
537
538 /* clean up */
539 release_all_client_connections(&tester);
540 release_all_server_connections(&tester);
541 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
542
543 ASSERT_SUCCESS(s_tester_clean_up(&tester));
544 return AWS_OP_SUCCESS;
545 }
546 AWS_TEST_CASE(connection_h2_prior_knowledge, s_test_connection_h2_prior_knowledge);
547
s_test_connection_h2_prior_knowledge_not_work_with_tls(struct aws_allocator * allocator,void * ctx)548 static int s_test_connection_h2_prior_knowledge_not_work_with_tls(struct aws_allocator *allocator, void *ctx) {
549 (void)ctx;
550 struct tester_options options = {
551 .alloc = allocator,
552 .no_connection = true,
553 .tls = true,
554 .server_alpn_list = "http/1.1",
555 };
556 struct tester tester;
557 ASSERT_SUCCESS(s_tester_init(&tester, &options));
558
559 /* Connect with prior knowledge */
560 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
561 s_client_connection_options_init_tester(&client_options, &tester);
562 ASSERT_SUCCESS(s_tls_client_opt_tester_init(&tester, "http/1.1", aws_byte_cursor_from_c_str("localhost")));
563 client_options.tls_options = &tester.client_tls_connection_options;
564 client_options.prior_knowledge_http2 = true;
565 tester.client_options = client_options;
566
567 tester.server_connection_num = 0;
568 tester.client_connection_num = 0;
569 /* prior knowledge only works with cleartext TCP */
570 ASSERT_FAILS(aws_http_client_connect(&tester.client_options));
571
572 ASSERT_SUCCESS(s_tester_clean_up(&tester));
573 return AWS_OP_SUCCESS;
574 }
575 AWS_TEST_CASE(connection_h2_prior_knowledge_not_work_with_tls, s_test_connection_h2_prior_knowledge_not_work_with_tls);
576
s_on_tester_negotiation_result(struct aws_channel_handler * handler,struct aws_channel_slot * slot,int err_code,void * user_data)577 static void s_on_tester_negotiation_result(
578 struct aws_channel_handler *handler,
579 struct aws_channel_slot *slot,
580 int err_code,
581 void *user_data) {
582
583 (void)slot;
584 (void)err_code;
585 struct tester *tester = (struct tester *)user_data;
586 struct aws_byte_buf src = aws_tls_handler_protocol(handler);
587 aws_byte_buf_init_copy(&tester->negotiated_protocol, tester->alloc, &src);
588 }
589
s_test_connection_customized_alpn(struct aws_allocator * allocator,void * ctx)590 static int s_test_connection_customized_alpn(struct aws_allocator *allocator, void *ctx) {
591 (void)ctx;
592 char customized_alpn_string[] = "myh2";
593 enum aws_http_version expected_version = AWS_HTTP_VERSION_2;
594 struct tester_options options = {
595 .alloc = allocator,
596 .no_connection = true,
597 .tls = true,
598 .server_alpn_list = "myh2;myh1.1;h2;http/1.1",
599 };
600 struct tester tester;
601 ASSERT_SUCCESS(s_tester_init(&tester, &options));
602
603 /* Connect with ALPN and the customized alpn string map */
604 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
605 s_client_connection_options_init_tester(&client_options, &tester);
606 ASSERT_SUCCESS(
607 s_tls_client_opt_tester_init(&tester, customized_alpn_string, aws_byte_cursor_from_c_str("localhost")));
608 aws_tls_connection_options_set_callbacks(
609 &tester.client_tls_connection_options, s_on_tester_negotiation_result, NULL, NULL, &tester);
610 client_options.tls_options = &tester.client_tls_connection_options;
611 /* create the alpn map */
612 struct aws_hash_table alpn_map;
613 AWS_ZERO_STRUCT(alpn_map);
614 ASSERT_SUCCESS(aws_http_alpn_map_init(allocator, &alpn_map));
615 /* We don't need to clean up the string as the map will own the string */
616 struct aws_string *alpn_string = aws_string_new_from_c_str(allocator, customized_alpn_string);
617 ASSERT_SUCCESS(aws_hash_table_put(&alpn_map, alpn_string, (void *)(size_t)expected_version, NULL));
618 client_options.alpn_string_map = &alpn_map;
619 tester.client_options = client_options;
620
621 tester.server_connection_num = 0;
622 tester.client_connection_num = 0;
623 ASSERT_SUCCESS(aws_http_client_connect(&tester.client_options));
624 /* We should be safe to free the map */
625 aws_hash_table_clean_up(&alpn_map);
626
627 /* Wait for server & client connections to finish setup */
628 tester.wait_client_connection_num = 1;
629 tester.wait_server_connection_num = 1;
630 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_setup_pred));
631
632 #ifndef __APPLE__ /* Server side ALPN doesn't work for MacOS */
633 /* Assert that we have the negotiated protocol and the expected version */
634 ASSERT_INT_EQUALS(tester.connection_version, expected_version);
635 ASSERT_TRUE(aws_byte_buf_eq_c_str(&tester.negotiated_protocol, customized_alpn_string));
636 #endif
637 /* clean up */
638 release_all_client_connections(&tester);
639 release_all_server_connections(&tester);
640 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
641
642 ASSERT_SUCCESS(s_tester_clean_up(&tester));
643 return AWS_OP_SUCCESS;
644 }
645 AWS_TEST_CASE(connection_customized_alpn, s_test_connection_customized_alpn);
646
s_test_connection_customized_alpn_error_with_unknow_return_string(struct aws_allocator * allocator,void * ctx)647 static int s_test_connection_customized_alpn_error_with_unknow_return_string(
648 struct aws_allocator *allocator,
649 void *ctx) {
650 (void)ctx;
651 char customized_alpn_string[] = "myh2";
652 struct tester_options options = {
653 .alloc = allocator,
654 .no_connection = true,
655 .tls = true,
656 .server_alpn_list = "myh2;myh1.1;h2;http/1.1",
657 };
658 struct tester tester;
659 ASSERT_SUCCESS(s_tester_init(&tester, &options));
660
661 /* Connect with ALPN and the customized alpn string map */
662 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
663 s_client_connection_options_init_tester(&client_options, &tester);
664 ASSERT_SUCCESS(
665 s_tls_client_opt_tester_init(&tester, customized_alpn_string, aws_byte_cursor_from_c_str("localhost")));
666 aws_tls_connection_options_set_callbacks(
667 &tester.client_tls_connection_options, s_on_tester_negotiation_result, NULL, NULL, &tester);
668 client_options.tls_options = &tester.client_tls_connection_options;
669 /* create the alpn map */
670 struct aws_hash_table alpn_map;
671 AWS_ZERO_STRUCT(alpn_map);
672 ASSERT_SUCCESS(aws_http_alpn_map_init(allocator, &alpn_map));
673 /* put an empty ALPN map, you will not found the returned string, and should error out when trying to connect*/
674 client_options.alpn_string_map = &alpn_map;
675 tester.client_options = client_options;
676
677 tester.server_connection_num = 0;
678 tester.client_connection_num = 0;
679 ASSERT_SUCCESS(aws_http_client_connect(&tester.client_options));
680 /* We should be safe to free the map */
681 aws_hash_table_clean_up(&alpn_map);
682
683 /* Wait for server & client connections to finish setup */
684 tester.wait_client_connection_num = 1;
685 tester.wait_server_connection_num = 1;
686
687 #ifndef __APPLE__ /* Server side ALPN doesn't work for MacOS */
688 ASSERT_FAILS(s_tester_wait(&tester, s_tester_connection_setup_pred));
689 /* Assert that we have the negotiated protocol and error returned from callback */
690 ASSERT_TRUE(aws_byte_buf_eq_c_str(&tester.negotiated_protocol, customized_alpn_string));
691 ASSERT_INT_EQUALS(aws_last_error(), AWS_ERROR_HTTP_UNSUPPORTED_PROTOCOL);
692 #else
693 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_setup_pred));
694 #endif
695 /* clean up */
696 release_all_client_connections(&tester);
697 release_all_server_connections(&tester);
698 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
699
700 ASSERT_SUCCESS(s_tester_clean_up(&tester));
701 return AWS_OP_SUCCESS;
702 }
703 AWS_TEST_CASE(
704 connection_customized_alpn_error_with_unknow_return_string,
705 s_test_connection_customized_alpn_error_with_unknow_return_string);
706
s_test_connection_destroy_server_with_connection_existing(struct aws_allocator * allocator,void * ctx)707 static int s_test_connection_destroy_server_with_connection_existing(struct aws_allocator *allocator, void *ctx) {
708 (void)ctx;
709 struct tester_options options = {
710 .alloc = allocator,
711 };
712 struct tester tester;
713 ASSERT_SUCCESS(s_tester_init(&tester, &options));
714
715 aws_http_server_release(tester.server);
716 /* wait for all connections to be shut down */
717 tester.wait_client_connection_is_shutdown = tester.client_connection_num;
718 tester.wait_server_connection_is_shutdown = tester.server_connection_num;
719 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
720
721 /* check the server is destroyed */
722 ASSERT_TRUE(tester.server_is_shutdown);
723 /* release memory */
724 release_all_client_connections(&tester);
725 release_all_server_connections(&tester);
726
727 ASSERT_SUCCESS(s_tester_clean_up(&tester));
728 return AWS_OP_SUCCESS;
729 }
730 AWS_TEST_CASE(
731 connection_destroy_server_with_connection_existing,
732 s_test_connection_destroy_server_with_connection_existing);
733
734 /* multiple connections */
s_test_connection_destroy_server_with_multiple_connections_existing(struct aws_allocator * allocator,void * ctx)735 static int s_test_connection_destroy_server_with_multiple_connections_existing(
736 struct aws_allocator *allocator,
737 void *ctx) {
738 (void)ctx;
739 struct tester_options options = {
740 .alloc = allocator,
741 };
742 struct tester tester;
743 ASSERT_SUCCESS(s_tester_init(&tester, &options));
744
745 /* more connections! */
746 int more_connection_num = 1;
747 /* set waiting condition */
748 tester.wait_client_connection_num += more_connection_num;
749 tester.wait_server_connection_num += more_connection_num;
750 /* connect */
751 for (int i = 0; i < more_connection_num; i++) {
752 ASSERT_SUCCESS(aws_http_client_connect(&tester.client_options));
753 }
754 /* wait for connections */
755 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_setup_pred));
756
757 aws_http_server_release(tester.server);
758 /* wait for all connections to be shut down */
759 tester.wait_client_connection_is_shutdown = tester.client_connection_num;
760 tester.wait_server_connection_is_shutdown = tester.server_connection_num;
761 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
762
763 /* check the server is destroyed */
764 ASSERT_TRUE(tester.server_is_shutdown);
765 /* release memory */
766 release_all_client_connections(&tester);
767 release_all_server_connections(&tester);
768
769 ASSERT_SUCCESS(s_tester_clean_up(&tester));
770 return AWS_OP_SUCCESS;
771 }
772 AWS_TEST_CASE(
773 connection_destroy_server_with_multiple_connections_existing,
774 s_test_connection_destroy_server_with_multiple_connections_existing);
775
s_block_task(struct aws_task * task,void * arg,enum aws_task_status status)776 static void s_block_task(struct aws_task *task, void *arg, enum aws_task_status status) {
777 (void)status;
778 /* sleep for 2 sec */
779 struct tester *tester = arg;
780 aws_thread_current_sleep(2000000000);
781 aws_mem_release(tester->alloc, task);
782 }
783
s_tester_on_new_client_connection_setup(struct aws_http_connection * connection,int error_code,void * user_data)784 static void s_tester_on_new_client_connection_setup(
785 struct aws_http_connection *connection,
786 int error_code,
787 void *user_data) {
788
789 struct tester *tester = user_data;
790 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
791 tester->new_client_setup_finished = true;
792 if (error_code) {
793 tester->client_wait_result = error_code;
794 goto done;
795 }
796 tester->new_client_connection = connection;
797 done:
798 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
799 aws_condition_variable_notify_one(&tester->wait_cvar);
800 }
801
s_tester_on_new_client_connection_shutdown(struct aws_http_connection * connection,int error_code,void * user_data)802 static void s_tester_on_new_client_connection_shutdown(
803 struct aws_http_connection *connection,
804 int error_code,
805 void *user_data) {
806
807 (void)connection;
808 (void)error_code;
809 struct tester *tester = user_data;
810 AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
811
812 tester->new_client_shut_down = true;
813
814 AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
815 aws_condition_variable_notify_one(&tester->wait_cvar);
816 }
817
s_tester_new_client_setup_pred(void * user_data)818 static bool s_tester_new_client_setup_pred(void *user_data) {
819 struct tester *tester = user_data;
820 return tester->new_client_setup_finished;
821 }
822
s_tester_new_client_shutdown_pred(void * user_data)823 static bool s_tester_new_client_shutdown_pred(void *user_data) {
824 struct tester *tester = user_data;
825 return tester->new_client_shut_down;
826 }
827
828 /* when we shutdown the server, no more new connection will be accepted */
s_test_connection_server_shutting_down_new_connection_setup_fail(struct aws_allocator * allocator,void * ctx)829 static int s_test_connection_server_shutting_down_new_connection_setup_fail(
830 struct aws_allocator *allocator,
831 void *ctx) {
832 (void)ctx;
833 struct tester_options options = {
834 .alloc = allocator,
835 };
836 struct tester tester;
837 ASSERT_SUCCESS(s_tester_init(&tester, &options));
838
839 /* Connect */
840 struct aws_socket_options socket_options = {
841 .type = AWS_SOCKET_STREAM,
842 .domain = AWS_SOCKET_LOCAL,
843 .connect_timeout_ms =
844 (uint32_t)aws_timestamp_convert(TESTER_TIMEOUT_SEC, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL),
845 };
846 /* create a new eventloop for the new connection and block the new connection. Waiting server to begin shutting
847 * down. */
848 struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 1, NULL);
849
850 /* get the first eventloop, which will be the eventloop for client to connect */
851 struct aws_event_loop *current_eventloop = aws_event_loop_group_get_loop_at(event_loop_group, 0);
852 struct aws_task *block_task = aws_mem_acquire(allocator, sizeof(struct aws_task));
853 aws_task_init(block_task, s_block_task, &tester, "wait_a_bit");
854 aws_event_loop_schedule_task_now(current_eventloop, block_task);
855
856 /* get the first eventloop of tester, which will be the eventloop for server listener socket, block the listener
857 * socket */
858 struct aws_event_loop *server_eventloop = aws_event_loop_group_get_loop_at(tester.event_loop_group, 0);
859 struct aws_task *server_block_task = aws_mem_acquire(allocator, sizeof(struct aws_task));
860 aws_task_init(server_block_task, s_block_task, &tester, "wait_a_bit");
861 aws_event_loop_schedule_task_now(server_eventloop, server_block_task);
862
863 struct aws_client_bootstrap_options bootstrap_options = {
864 .event_loop_group = event_loop_group,
865 .host_resolver = tester.host_resolver,
866 };
867 struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
868 struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
869 client_options.allocator = tester.alloc;
870 client_options.bootstrap = bootstrap;
871 client_options.host_name = aws_byte_cursor_from_c_str(tester.endpoint.address);
872 client_options.port = tester.endpoint.port;
873 client_options.socket_options = &socket_options;
874 client_options.user_data = &tester;
875 client_options.on_setup = s_tester_on_new_client_connection_setup;
876 client_options.on_shutdown = s_tester_on_new_client_connection_shutdown;
877
878 /* new connection will be blocked for 2 sec */
879 tester.wait_server_connection_num++;
880 ASSERT_SUCCESS(aws_http_client_connect(&client_options));
881
882 /* shutting down the server */
883 aws_http_server_release(tester.server);
884 /* the server side connection failed with error code, closed */
885 ASSERT_FAILS(s_tester_wait(&tester, s_tester_connection_setup_pred));
886 /* wait for the client side connection */
887 s_tester_wait(&tester, s_tester_new_client_setup_pred);
888
889 if (tester.new_client_connection && !tester.client_connection_is_shutdown) {
890 /* wait for it to shut down, we do not need to call shut down, the socket will know */
891 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_new_client_shutdown_pred));
892 }
893
894 if (tester.new_client_connection) {
895 aws_http_connection_release(tester.new_client_connection);
896 }
897
898 /* wait for the old connections to be shut down */
899 tester.wait_client_connection_is_shutdown = tester.client_connection_num;
900 tester.wait_server_connection_is_shutdown = tester.server_connection_num;
901 /* assert the new connection fail to set up in user's perspective */
902 ASSERT_TRUE(tester.client_connection_num == 1);
903 ASSERT_TRUE(tester.server_connection_num == 1);
904 ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
905
906 /* release memory */
907 release_all_client_connections(&tester);
908 release_all_server_connections(&tester);
909 aws_client_bootstrap_release(bootstrap);
910 aws_event_loop_group_release(event_loop_group);
911 ASSERT_SUCCESS(s_tester_clean_up(&tester));
912
913 return AWS_OP_SUCCESS;
914 }
915 AWS_TEST_CASE(
916 connection_server_shutting_down_new_connection_setup_fail,
917 s_test_connection_server_shutting_down_new_connection_setup_fail);
918