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