@@ -2260,30 +2260,33 @@ static struct aws_input_stream_vtable s_slow_stream_vtable = {
22602260 .get_length = s_slow_stream_get_length ,
22612261};
22622262
2263+ static void s_slow_body_sender_init (struct slow_body_sender * body_sender ) {
2264+ /* set up request whose body won't send immediately */
2265+ struct aws_input_stream empty_stream_base ;
2266+ AWS_ZERO_STRUCT (empty_stream_base );
2267+ body_sender -> base = empty_stream_base ;
2268+ body_sender -> status .is_end_of_stream = false;
2269+ body_sender -> status .is_valid = true;
2270+ struct aws_byte_cursor body = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL ("write more tests" );
2271+ body_sender -> cursor = body ;
2272+ body_sender -> delay_ticks = 5 ;
2273+ body_sender -> bytes_per_tick = 1 ;
2274+
2275+ body_sender -> base .vtable = & s_slow_stream_vtable ;
2276+ aws_ref_count_init (
2277+ & body_sender -> base .ref_count , & body_sender , (aws_simple_completion_callback * )s_slow_stream_destroy );
2278+ }
2279+
22632280/* It should be fine to receive a response before the request has finished sending */
22642281H1_CLIENT_TEST_CASE (h1_client_response_arrives_before_request_done_sending_is_ok ) {
22652282 (void )ctx ;
22662283 struct tester tester ;
22672284 ASSERT_SUCCESS (s_tester_init (& tester , allocator ));
22682285
22692286 /* set up request whose body won't send immediately */
2270- struct aws_input_stream empty_stream_base ;
2271- AWS_ZERO_STRUCT (empty_stream_base );
2272- struct slow_body_sender body_sender = {
2273- .base = empty_stream_base ,
2274- .status =
2275- {
2276- .is_end_of_stream = false,
2277- .is_valid = true,
2278- },
2279- .cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL ("write more tests" ),
2280- .delay_ticks = 5 ,
2281- .bytes_per_tick = 1 ,
2282- };
2283- body_sender .base .vtable = & s_slow_stream_vtable ;
2284- aws_ref_count_init (
2285- & body_sender .base .ref_count , & body_sender , (aws_simple_completion_callback * )s_slow_stream_destroy );
2286-
2287+ struct slow_body_sender body_sender ;
2288+ AWS_ZERO_STRUCT (body_sender );
2289+ s_slow_body_sender_init (& body_sender );
22872290 struct aws_input_stream * body_stream = & body_sender .base ;
22882291
22892292 struct aws_http_header headers [] = {
@@ -4156,3 +4159,127 @@ H1_CLIENT_TEST_CASE(h1_client_switching_protocols_requires_downstream_handler) {
41564159 ASSERT_SUCCESS (s_tester_clean_up (& tester ));
41574160 return AWS_OP_SUCCESS ;
41584161}
4162+
4163+ H1_CLIENT_TEST_CASE (h1_client_connection_close_before_request_finishes ) {
4164+ (void )ctx ;
4165+ struct tester tester ;
4166+ ASSERT_SUCCESS (s_tester_init (& tester , allocator ));
4167+
4168+ /* set up request whose body won't send immediately */
4169+ struct slow_body_sender body_sender ;
4170+ AWS_ZERO_STRUCT (body_sender );
4171+ s_slow_body_sender_init (& body_sender );
4172+ struct aws_input_stream * body_stream = & body_sender .base ;
4173+
4174+ struct aws_http_header headers [] = {
4175+ {
4176+ .name = aws_byte_cursor_from_c_str ("Content-Length" ),
4177+ .value = aws_byte_cursor_from_c_str ("16" ),
4178+ },
4179+ };
4180+
4181+ struct aws_http_message * request = aws_http_message_new_request (allocator );
4182+ ASSERT_NOT_NULL (request );
4183+ ASSERT_SUCCESS (aws_http_message_set_request_method (request , aws_byte_cursor_from_c_str ("PUT" )));
4184+ ASSERT_SUCCESS (aws_http_message_set_request_path (request , aws_byte_cursor_from_c_str ("/plan.txt" )));
4185+ ASSERT_SUCCESS (aws_http_message_add_header_array (request , headers , AWS_ARRAY_SIZE (headers )));
4186+ aws_http_message_set_body_stream (request , body_stream );
4187+
4188+ struct client_stream_tester stream_tester ;
4189+ ASSERT_SUCCESS (s_stream_tester_init (& stream_tester , & tester , request ));
4190+
4191+ /* send head of request */
4192+ testing_channel_run_currently_queued_tasks (& tester .testing_channel );
4193+
4194+ /* Ensure the request can be destroyed after request is sent */
4195+ aws_http_message_destroy (request );
4196+ aws_input_stream_release (body_stream );
4197+
4198+ /* send close connection response */
4199+ ASSERT_SUCCESS (testing_channel_push_read_str (
4200+ & tester .testing_channel ,
4201+ "HTTP/1.1 404 Not Found\r\n"
4202+ "Date: Fri, 01 Mar 2019 17:18:55 GMT\r\n"
4203+ "\r\n" ));
4204+
4205+ testing_channel_run_currently_queued_tasks (& tester .testing_channel );
4206+
4207+ aws_channel_shutdown (tester .testing_channel .channel , AWS_ERROR_SUCCESS );
4208+ /* Wait for channel to finish shutdown */
4209+ testing_channel_drain_queued_tasks (& tester .testing_channel );
4210+ /* check result, should not receive any body */
4211+ const char * expected = "PUT /plan.txt HTTP/1.1\r\n"
4212+ "Content-Length: 16\r\n"
4213+ "\r\n" ;
4214+ ASSERT_SUCCESS (testing_channel_check_written_messages_str (& tester .testing_channel , allocator , expected ));
4215+
4216+ ASSERT_TRUE (stream_tester .complete );
4217+ ASSERT_INT_EQUALS (AWS_ERROR_SUCCESS , stream_tester .on_complete_error_code );
4218+
4219+ /* clean up */
4220+ client_stream_tester_clean_up (& stream_tester );
4221+ ASSERT_SUCCESS (s_tester_clean_up (& tester ));
4222+ return AWS_OP_SUCCESS ;
4223+ }
4224+
4225+ /* When response has `connection: close` any further request body should not be sent. */
4226+ H1_CLIENT_TEST_CASE (h1_client_response_close_connection_before_request_finishes ) {
4227+ (void )ctx ;
4228+ struct tester tester ;
4229+ ASSERT_SUCCESS (s_tester_init (& tester , allocator ));
4230+
4231+ /* set up request whose body won't send immediately */
4232+ struct slow_body_sender body_sender ;
4233+ AWS_ZERO_STRUCT (body_sender );
4234+ s_slow_body_sender_init (& body_sender );
4235+ struct aws_input_stream * body_stream = & body_sender .base ;
4236+
4237+ struct aws_http_header headers [] = {
4238+ {
4239+ .name = aws_byte_cursor_from_c_str ("Content-Length" ),
4240+ .value = aws_byte_cursor_from_c_str ("16" ),
4241+ },
4242+ };
4243+
4244+ struct aws_http_message * request = aws_http_message_new_request (allocator );
4245+ ASSERT_NOT_NULL (request );
4246+ ASSERT_SUCCESS (aws_http_message_set_request_method (request , aws_byte_cursor_from_c_str ("PUT" )));
4247+ ASSERT_SUCCESS (aws_http_message_set_request_path (request , aws_byte_cursor_from_c_str ("/plan.txt" )));
4248+ ASSERT_SUCCESS (aws_http_message_add_header_array (request , headers , AWS_ARRAY_SIZE (headers )));
4249+ aws_http_message_set_body_stream (request , body_stream );
4250+
4251+ struct client_stream_tester stream_tester ;
4252+ ASSERT_SUCCESS (s_stream_tester_init (& stream_tester , & tester , request ));
4253+
4254+ /* send head of request */
4255+ testing_channel_run_currently_queued_tasks (& tester .testing_channel );
4256+
4257+ /* Ensure the request can be destroyed after request is sent */
4258+ aws_http_message_destroy (request );
4259+ aws_input_stream_release (body_stream );
4260+
4261+ /* send close connection response */
4262+ ASSERT_SUCCESS (testing_channel_push_read_str (
4263+ & tester .testing_channel ,
4264+ "HTTP/1.1 404 Not Found\r\n"
4265+ "Date: Fri, 01 Mar 2019 17:18:55 GMT\r\n"
4266+ "Connection: close\r\n"
4267+ "\r\n" ));
4268+
4269+ testing_channel_drain_queued_tasks (& tester .testing_channel );
4270+ /* check result, should not receive any body */
4271+ const char * expected = "PUT /plan.txt HTTP/1.1\r\n"
4272+ "Content-Length: 16\r\n"
4273+ "\r\n" ;
4274+ ASSERT_SUCCESS (testing_channel_check_written_messages_str (& tester .testing_channel , allocator , expected ));
4275+ /* Check if the testing channel has shut down. */
4276+ ASSERT_TRUE (testing_channel_is_shutdown_completed (& tester .testing_channel ));
4277+
4278+ ASSERT_TRUE (stream_tester .complete );
4279+ ASSERT_INT_EQUALS (AWS_ERROR_SUCCESS , stream_tester .on_complete_error_code );
4280+
4281+ /* clean up */
4282+ client_stream_tester_clean_up (& stream_tester );
4283+ ASSERT_SUCCESS (s_tester_clean_up (& tester ));
4284+ return AWS_OP_SUCCESS ;
4285+ }
0 commit comments