Skip to content

Commit 5bda807

Browse files
Fix proxies connect and tests (#198)
Ignore connection: close on 200/OK responses to a CONNECT Request, since the proxy is obviously drunk and needs to hail an uber to get home from the bar safely. Fix the broken tests from the tcp back pressure refactor in aws-c-io.
1 parent 2196e04 commit 5bda807

File tree

11 files changed

+49
-23
lines changed

11 files changed

+49
-23
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
- '!master'
88

99
env:
10-
BUILDER_VERSION: v0.5.3
10+
BUILDER_VERSION: v0.5.8
1111
BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net
1212
PACKAGE_NAME: aws-c-http
1313
LINUX_BASE_IMAGE: ubuntu-16-x64

builder.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,8 @@
1313
"downstream": [
1414
{ "name": "aws-c-auth" }
1515
],
16-
"test": [
17-
["ctest", "{build_dir}", "-v", "--output-on-failure"],
16+
"test_steps": [
17+
"test",
1818
["{python}", "{project_dir}/integration-testing/http_client_test.py", "{install_dir}/bin/elasticurl{exe}"]
19-
],
20-
"cmake_args": [
21-
"-DS2N_NO_PQ_ASM=ON"
2219
]
2320
}

include/aws/http/private/http_impl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ enum aws_http_method {
2626
AWS_HTTP_METHOD_UNKNOWN, /* Unrecognized value. */
2727
AWS_HTTP_METHOD_GET,
2828
AWS_HTTP_METHOD_HEAD,
29+
AWS_HTTP_METHOD_CONNECT,
2930
AWS_HTTP_METHOD_COUNT, /* Number of enums */
3031
};
3132

@@ -50,6 +51,7 @@ enum aws_http_status {
5051
AWS_HTTP_STATUS_UNKNOWN = -1, /* Invalid status code. Not using 0 because it's technically a legal value */
5152
AWS_HTTP_STATUS_100_CONTINUE = 100,
5253
AWS_HTTP_STATUS_101_SWITCHING_PROTOCOLS = 101,
54+
AWS_HTTP_STATUS_200_OK = 200,
5355
AWS_HTTP_STATUS_204_NO_CONTENT = 204,
5456
AWS_HTTP_STATUS_304_NOT_MODIFIED = 304,
5557
};

source/h1_connection.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,14 @@ static int s_decoder_on_header(const struct aws_h1_decoded_header *header, void
985985
/* RFC-7230 section 6.1.
986986
* "Connection: close" header signals that a connection will not persist after the current request/response */
987987
if (header->name == AWS_HTTP_HEADER_CONNECTION) {
988-
if (aws_byte_cursor_eq_c_str(&header->value_data, "close")) {
988+
/* Certain L7 proxies send a connection close header on a 200/OK response to a CONNECT request. This is nutty
989+
* behavior, but the obviously desired behavior on a 200 CONNECT response is to leave the connection open
990+
* for the tunneling. */
991+
bool ignore_connection_close = incoming_stream->base.request_method == AWS_HTTP_METHOD_CONNECT &&
992+
incoming_stream->base.client_data &&
993+
incoming_stream->base.client_data->response_status == AWS_HTTP_STATUS_200_OK;
994+
995+
if (!ignore_connection_close && aws_byte_cursor_eq_c_str_ignore_case(&header->value_data, "close")) {
989996
AWS_LOGF_TRACE(
990997
AWS_LS_HTTP_STREAM,
991998
"id=%p: Received 'Connection: close' header. This will be the final stream on this connection.",

source/h1_stream.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <aws/http/private/h1_stream.h>
1616

1717
#include <aws/http/private/connection_impl.h>
18+
1819
#include <aws/io/logging.h>
1920

2021
static void s_stream_destroy(struct aws_http_stream *stream_base) {

source/http.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ static struct aws_byte_cursor s_method_enum_to_str[AWS_HTTP_METHOD_COUNT]; /* fo
202202
static void s_methods_init(struct aws_allocator *alloc) {
203203
s_method_enum_to_str[AWS_HTTP_METHOD_GET] = aws_http_method_get;
204204
s_method_enum_to_str[AWS_HTTP_METHOD_HEAD] = aws_http_method_head;
205+
s_method_enum_to_str[AWS_HTTP_METHOD_CONNECT] = aws_http_method_connect;
205206

206207
s_init_str_to_enum_hash_table(
207208
&s_method_str_to_enum,

tests/proxy_test_helper.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,9 @@ int proxy_tester_create_testing_channel_connection(struct proxy_tester *tester)
254254
tester->testing_channel->channel_shutdown = s_testing_channel_shutdown_callback;
255255
tester->testing_channel->channel_shutdown_user_data = tester;
256256

257-
struct aws_http_connection *connection = aws_http_connection_new_http1_1_client(tester->alloc, SIZE_MAX);
257+
/* Use small window so that we can observe it opening in tests.
258+
* Channel may wait until the window is small before issuing the increment command. */
259+
struct aws_http_connection *connection = aws_http_connection_new_http1_1_client(tester->alloc, 256);
258260
ASSERT_NOT_NULL(connection);
259261

260262
connection->user_data = tester->http_bootstrap->user_data;
@@ -266,9 +268,9 @@ int proxy_tester_create_testing_channel_connection(struct proxy_tester *tester)
266268
ASSERT_SUCCESS(aws_channel_slot_insert_end(tester->testing_channel->channel, slot));
267269
ASSERT_SUCCESS(aws_channel_slot_set_handler(slot, &connection->channel_handler));
268270
connection->vtable->on_channel_handler_installed(&connection->channel_handler, slot);
271+
testing_channel_drain_queued_tasks(tester->testing_channel);
269272

270273
tester->client_connection = connection;
271-
testing_channel_drain_queued_tasks(tester->testing_channel);
272274

273275
return AWS_OP_SUCCESS;
274276
}
@@ -309,7 +311,9 @@ int proxy_tester_send_connect_response(struct proxy_tester *tester) {
309311
if (tester->failure_type == PTFT_CONNECT_REQUEST) {
310312
response_string = "HTTP/1.0 401 Unauthorized\r\n\r\n";
311313
} else {
312-
response_string = "HTTP/1.0 200 Connection established\r\n\r\n";
314+
/* adding close here because it's an edge case we need to exercise. The desired behavior is that it has
315+
* absolutely no effect. */
316+
response_string = "HTTP/1.0 200 Connection established\r\nconnection: close\r\n\r\n";
313317
}
314318

315319
/* send response */

tests/test_connection.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ static bool s_tester_new_client_shutdown_pred(void *user_data) {
530530
return tester->new_client_shut_down;
531531
}
532532

533-
/* when we shutdown the server, no more new connection will be accept */
533+
/* when we shutdown the server, no more new connection will be accepted */
534534
static int s_test_connection_server_shutting_down_new_connection_setup_fail(
535535
struct aws_allocator *allocator,
536536
void *ctx) {
@@ -591,9 +591,13 @@ static int s_test_connection_server_shutting_down_new_connection_setup_fail(
591591
ASSERT_FAILS(s_tester_wait(&tester, s_tester_connection_setup_pred));
592592
/* wait for the client side connection */
593593
s_tester_wait(&tester, s_tester_new_client_setup_pred);
594-
if (tester.new_client_connection) {
594+
595+
if (tester.new_client_connection && !tester.client_connection_is_shutdown) {
595596
/* wait for it to shut down, we do not need to call shut down, the socket will know */
596597
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_new_client_shutdown_pred));
598+
}
599+
600+
if (tester.new_client_connection) {
597601
aws_http_connection_release(tester.new_client_connection);
598602
}
599603

tests/test_h1_client.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ static int s_tester_init(struct tester *tester, struct aws_allocator *alloc) {
7171
struct aws_testing_channel_options test_channel_options = {.clock_fn = aws_high_res_clock_get_ticks};
7272
ASSERT_SUCCESS(testing_channel_init(&tester->testing_channel, alloc, &test_channel_options));
7373

74-
tester->connection = aws_http_connection_new_http1_1_client(alloc, SIZE_MAX);
74+
/* Use small window so that we can observe it opening in tests.
75+
* Channel may wait until the window is small before issuing the increment command. */
76+
tester->connection = aws_http_connection_new_http1_1_client(alloc, 256);
7577
ASSERT_NOT_NULL(tester->connection);
7678

7779
struct aws_channel_slot *slot = aws_channel_slot_new(tester->testing_channel.channel);
@@ -1501,7 +1503,7 @@ H1_CLIENT_TEST_CASE(h1_client_window_shrinks_if_user_says_so) {
15011503
/* check result */
15021504
size_t window_update = testing_channel_last_window_update(&tester.testing_channel);
15031505
size_t message_sans_body = strlen(response_str) - 9;
1504-
ASSERT_TRUE(window_update == message_sans_body);
1506+
ASSERT_UINT_EQUALS(message_sans_body, window_update);
15051507

15061508
/* clean up */
15071509
ASSERT_SUCCESS(s_response_tester_clean_up(&response));

tests/test_proxy.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,8 @@ static int s_test_https_proxy_connection_failure_tls(struct aws_allocator *alloc
326326

327327
ASSERT_SUCCESS(proxy_tester_verify_connection_attempt_was_to_proxy(
328328
&tester, aws_byte_cursor_from_c_str(s_proxy_host_name), s_proxy_port));
329-
ASSERT_TRUE(tester.client_connection == NULL);
330-
ASSERT_TRUE(tester.wait_result != AWS_ERROR_SUCCESS);
329+
ASSERT_NULL(tester.client_connection);
330+
ASSERT_TRUE(AWS_ERROR_SUCCESS != tester.wait_result);
331331

332332
ASSERT_SUCCESS(proxy_tester_clean_up(&tester));
333333

tests/test_websocket_handler.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
# pragma warning(disable : 4204) /* non-constant aggregate initializer */
2525
#endif
2626

27+
/* Use small window so that we can observe it opening in tests.
28+
* Channel may wait until the window is small before issuing the increment command. */
29+
static const size_t s_default_initial_window_size = 256;
30+
2731
#define TEST_CASE(NAME) \
2832
AWS_TEST_CASE(NAME, s_test_##NAME); \
2933
static int s_test_##NAME(struct aws_allocator *allocator, void *ctx)
@@ -487,7 +491,7 @@ static int s_tester_init(struct tester *tester, struct aws_allocator *alloc) {
487491
struct aws_websocket_handler_options ws_options = {
488492
.allocator = alloc,
489493
.channel = tester->testing_channel.channel,
490-
.initial_window_size = SIZE_MAX,
494+
.initial_window_size = s_default_initial_window_size,
491495
.user_data = tester,
492496
.on_incoming_frame_begin = s_on_incoming_frame_begin,
493497
.on_incoming_frame_payload = s_on_incoming_frame_payload,
@@ -496,6 +500,7 @@ static int s_tester_init(struct tester *tester, struct aws_allocator *alloc) {
496500
};
497501
tester->websocket = aws_websocket_handler_new(&ws_options);
498502
ASSERT_NOT_NULL(tester->websocket);
503+
testing_channel_drain_queued_tasks(&tester->testing_channel);
499504

500505
aws_websocket_decoder_init(&tester->written_frame_decoder, s_on_written_frame, s_on_written_frame_payload, tester);
501506
aws_websocket_encoder_init(&tester->readpush_encoder, s_stream_readpush_payload, tester);
@@ -530,6 +535,8 @@ static int s_install_downstream_handler(struct tester *tester, size_t initial_wi
530535
tester->is_midchannel_handler = true;
531536

532537
ASSERT_SUCCESS(testing_channel_install_downstream_handler(&tester->testing_channel, initial_window));
538+
testing_channel_drain_queued_tasks(&tester->testing_channel);
539+
533540
return AWS_OP_SUCCESS;
534541
}
535542

@@ -1693,6 +1700,7 @@ static int s_window_manual_increment_common(struct aws_allocator *allocator, boo
16931700

16941701
/* Assert that window did not fully re-open*/
16951702
uint64_t frame_minus_payload_size = aws_websocket_frame_encoded_size(&pushing.def) - pushing.def.payload_length;
1703+
16961704
ASSERT_UINT_EQUALS(frame_minus_payload_size, testing_channel_last_window_update(&tester.testing_channel));
16971705

16981706
/* Manually increment window */
@@ -1722,7 +1730,7 @@ TEST_CASE(websocket_midchannel_sanity_check) {
17221730
(void)ctx;
17231731
struct tester tester;
17241732
ASSERT_SUCCESS(s_tester_init(&tester, allocator));
1725-
ASSERT_SUCCESS(s_install_downstream_handler(&tester, SIZE_MAX));
1733+
ASSERT_SUCCESS(s_install_downstream_handler(&tester, s_default_initial_window_size));
17261734
ASSERT_SUCCESS(s_tester_clean_up(&tester));
17271735
return AWS_OP_SUCCESS;
17281736
}
@@ -1731,7 +1739,7 @@ TEST_CASE(websocket_midchannel_write_message) {
17311739
(void)ctx;
17321740
struct tester tester;
17331741
ASSERT_SUCCESS(s_tester_init(&tester, allocator));
1734-
ASSERT_SUCCESS(s_install_downstream_handler(&tester, SIZE_MAX));
1742+
ASSERT_SUCCESS(s_install_downstream_handler(&tester, s_default_initial_window_size));
17351743

17361744
/* Write data */
17371745
struct aws_byte_cursor writing = aws_byte_cursor_from_c_str("My hat it has three corners");
@@ -1749,7 +1757,7 @@ TEST_CASE(websocket_midchannel_write_multiple_messages) {
17491757
(void)ctx;
17501758
struct tester tester;
17511759
ASSERT_SUCCESS(s_tester_init(&tester, allocator));
1752-
ASSERT_SUCCESS(s_install_downstream_handler(&tester, SIZE_MAX));
1760+
ASSERT_SUCCESS(s_install_downstream_handler(&tester, s_default_initial_window_size));
17531761

17541762
struct aws_byte_cursor writing[] = {
17551763
aws_byte_cursor_from_c_str("My hat it has three corners."),
@@ -1774,7 +1782,7 @@ TEST_CASE(websocket_midchannel_write_huge_message) {
17741782
(void)ctx;
17751783
struct tester tester;
17761784
ASSERT_SUCCESS(s_tester_init(&tester, allocator));
1777-
ASSERT_SUCCESS(s_install_downstream_handler(&tester, SIZE_MAX));
1785+
ASSERT_SUCCESS(s_install_downstream_handler(&tester, s_default_initial_window_size));
17781786

17791787
/* Fill big buffer with random data */
17801788
struct aws_byte_buf writing;
@@ -1801,7 +1809,7 @@ TEST_CASE(websocket_midchannel_read_message) {
18011809
(void)ctx;
18021810
struct tester tester;
18031811
ASSERT_SUCCESS(s_tester_init(&tester, allocator));
1804-
ASSERT_SUCCESS(s_install_downstream_handler(&tester, SIZE_MAX));
1812+
ASSERT_SUCCESS(s_install_downstream_handler(&tester, s_default_initial_window_size));
18051813

18061814
struct readpush_frame pushing = {
18071815
.payload = aws_byte_cursor_from_c_str("Hello hello can you hear me Joe?"),
@@ -1822,7 +1830,7 @@ TEST_CASE(websocket_midchannel_read_multiple_messages) {
18221830
(void)ctx;
18231831
struct tester tester;
18241832
ASSERT_SUCCESS(s_tester_init(&tester, allocator));
1825-
ASSERT_SUCCESS(s_install_downstream_handler(&tester, SIZE_MAX));
1833+
ASSERT_SUCCESS(s_install_downstream_handler(&tester, s_default_initial_window_size));
18261834

18271835
/* Read a mix of different frame types, most of which shouldn't get passed along to next handler. */
18281836
struct readpush_frame pushing[] = {

0 commit comments

Comments
 (0)