@@ -6025,6 +6025,244 @@ TEST_CASE(h2_client_batch_manual_window_update) {
60256025 return s_tester_clean_up ();
60266026}
60276027
6028+ /* Test that on_h2_remote_end_stream fires when remote peer sends END_STREAM */
6029+ TEST_CASE (h2_client_on_h2_remote_end_stream_fires ) {
6030+ ASSERT_SUCCESS (s_tester_init (allocator , ctx ));
6031+
6032+ /* get connection preface and acks out of the way */
6033+ ASSERT_SUCCESS (h2_fake_peer_send_connection_preface_default_settings (& s_tester .peer ));
6034+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6035+
6036+ /* send request */
6037+ struct aws_http_message * request = aws_http2_message_new_request (allocator );
6038+ ASSERT_NOT_NULL (request );
6039+
6040+ struct aws_http_header request_headers_src [] = {
6041+ DEFINE_HEADER (":method" , "GET" ),
6042+ DEFINE_HEADER (":scheme" , "https" ),
6043+ DEFINE_HEADER (":path" , "/" ),
6044+ };
6045+ aws_http_message_add_header_array (request , request_headers_src , AWS_ARRAY_SIZE (request_headers_src ));
6046+
6047+ bool track_on_h2_remote_end_stream = true;
6048+ struct client_stream_tester_options tester_options = {
6049+ .request = request ,
6050+ .connection = s_tester .connection ,
6051+ .on_h2_remote_end_stream = & track_on_h2_remote_end_stream ,
6052+ };
6053+ struct client_stream_tester stream_tester ;
6054+ ASSERT_SUCCESS (client_stream_tester_init (& stream_tester , allocator , & tester_options ));
6055+
6056+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6057+ uint32_t stream_id = aws_http_stream_get_id (stream_tester .stream );
6058+
6059+ /* fake peer sends response with END_STREAM */
6060+ struct aws_http_header response_headers_src [] = {
6061+ DEFINE_HEADER (":status" , "200" ),
6062+ };
6063+
6064+ struct aws_http_headers * response_headers = aws_http_headers_new (allocator );
6065+ aws_http_headers_add_array (response_headers , response_headers_src , AWS_ARRAY_SIZE (response_headers_src ));
6066+
6067+ struct aws_h2_frame * response_frame =
6068+ aws_h2_frame_new_headers (allocator , stream_id , response_headers , true /*end_stream*/ , 0 , NULL );
6069+ ASSERT_SUCCESS (h2_fake_peer_send_frame (& s_tester .peer , response_frame ));
6070+
6071+ /* validate that both callbacks fired */
6072+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6073+ ASSERT_TRUE (stream_tester .on_h2_remote_end_stream_invoked );
6074+ ASSERT_TRUE (stream_tester .complete );
6075+ ASSERT_INT_EQUALS (AWS_ERROR_SUCCESS , stream_tester .on_complete_error_code );
6076+
6077+ /* clean up */
6078+ aws_http_headers_release (response_headers );
6079+ aws_http_message_release (request );
6080+ client_stream_tester_clean_up (& stream_tester );
6081+ return s_tester_clean_up ();
6082+ }
6083+
6084+ /* Test that on_h2_remote_end_stream does NOT fire when RST_STREAM is received */
6085+ TEST_CASE (h2_client_on_h2_remote_end_stream_not_fired_on_rst_stream ) {
6086+ ASSERT_SUCCESS (s_tester_init (allocator , ctx ));
6087+
6088+ /* get connection preface and acks out of the way */
6089+ ASSERT_SUCCESS (h2_fake_peer_send_connection_preface_default_settings (& s_tester .peer ));
6090+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6091+
6092+ /* send request */
6093+ struct aws_http_message * request = aws_http2_message_new_request (allocator );
6094+ ASSERT_NOT_NULL (request );
6095+
6096+ struct aws_http_header request_headers_src [] = {
6097+ DEFINE_HEADER (":method" , "GET" ),
6098+ DEFINE_HEADER (":scheme" , "https" ),
6099+ DEFINE_HEADER (":path" , "/" ),
6100+ };
6101+ aws_http_message_add_header_array (request , request_headers_src , AWS_ARRAY_SIZE (request_headers_src ));
6102+
6103+ bool track_on_h2_remote_end_stream = true;
6104+ struct client_stream_tester_options tester_options = {
6105+ .request = request ,
6106+ .connection = s_tester .connection ,
6107+ .on_h2_remote_end_stream = & track_on_h2_remote_end_stream ,
6108+ };
6109+ struct client_stream_tester stream_tester ;
6110+ ASSERT_SUCCESS (client_stream_tester_init (& stream_tester , allocator , & tester_options ));
6111+
6112+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6113+ uint32_t stream_id = aws_http_stream_get_id (stream_tester .stream );
6114+
6115+ /* fake peer sends RST_STREAM instead of END_STREAM */
6116+ struct aws_h2_frame * rst_frame = aws_h2_frame_new_rst_stream (allocator , stream_id , AWS_HTTP2_ERR_INTERNAL_ERROR );
6117+ ASSERT_SUCCESS (h2_fake_peer_send_frame (& s_tester .peer , rst_frame ));
6118+
6119+ /* validate that on_h2_remote_end_stream did NOT fire, but on_complete did */
6120+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6121+ ASSERT_FALSE (stream_tester .on_h2_remote_end_stream_invoked );
6122+ ASSERT_TRUE (stream_tester .complete );
6123+ ASSERT_INT_EQUALS (AWS_ERROR_HTTP_RST_STREAM_RECEIVED , stream_tester .on_complete_error_code );
6124+
6125+ /* clean up */
6126+ aws_http_message_release (request );
6127+ client_stream_tester_clean_up (& stream_tester );
6128+ return s_tester_clean_up ();
6129+ }
6130+
6131+ /* Test early server response (server sends END_STREAM before client finishes) */
6132+ TEST_CASE (h2_client_on_h2_remote_end_stream_early_server_response ) {
6133+ ASSERT_SUCCESS (s_tester_init (allocator , ctx ));
6134+
6135+ /* get connection preface and acks out of the way */
6136+ ASSERT_SUCCESS (h2_fake_peer_send_connection_preface_default_settings (& s_tester .peer ));
6137+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6138+
6139+ /* create request with body that will stall */
6140+ struct aws_http_message * request = aws_http2_message_new_request (allocator );
6141+ ASSERT_NOT_NULL (request );
6142+
6143+ struct aws_http_header request_headers_src [] = {
6144+ DEFINE_HEADER (":method" , "POST" ),
6145+ DEFINE_HEADER (":scheme" , "https" ),
6146+ DEFINE_HEADER (":path" , "/upload" ),
6147+ };
6148+ aws_http_message_add_header_array (request , request_headers_src , AWS_ARRAY_SIZE (request_headers_src ));
6149+
6150+ const char * body = "request body data" ;
6151+ struct aws_byte_cursor body_cursor = aws_byte_cursor_from_c_str (body );
6152+ struct aws_input_stream * body_stream = aws_input_stream_new_tester (allocator , body_cursor );
6153+ aws_input_stream_tester_set_max_bytes_per_read (body_stream , 1 ); /* Stall the body */
6154+ aws_http_message_set_body_stream (request , body_stream );
6155+
6156+ bool track_on_h2_remote_end_stream = true;
6157+ struct client_stream_tester_options tester_options = {
6158+ .request = request ,
6159+ .connection = s_tester .connection ,
6160+ .on_h2_remote_end_stream = & track_on_h2_remote_end_stream ,
6161+ };
6162+ struct client_stream_tester stream_tester ;
6163+ ASSERT_SUCCESS (client_stream_tester_init (& stream_tester , allocator , & tester_options ));
6164+
6165+ /* Execute 1 event-loop tick, HEADERS should be sent but body stalled */
6166+ testing_channel_run_currently_queued_tasks (& s_tester .testing_channel );
6167+ uint32_t stream_id = aws_http_stream_get_id (stream_tester .stream );
6168+
6169+ /* fake peer sends complete response while client is still sending */
6170+ struct aws_http_header response_headers_src [] = {
6171+ DEFINE_HEADER (":status" , "200" ),
6172+ };
6173+
6174+ struct aws_http_headers * response_headers = aws_http_headers_new (allocator );
6175+ aws_http_headers_add_array (response_headers , response_headers_src , AWS_ARRAY_SIZE (response_headers_src ));
6176+
6177+ struct aws_h2_frame * response_frame =
6178+ aws_h2_frame_new_headers (allocator , stream_id , response_headers , true /*end_stream*/ , 0 , NULL );
6179+ ASSERT_SUCCESS (h2_fake_peer_send_frame (& s_tester .peer , response_frame ));
6180+
6181+ testing_channel_run_currently_queued_tasks (& s_tester .testing_channel );
6182+
6183+ /* At this point, on_h2_remote_end_stream should have fired, but on_complete should NOT (client still sending) */
6184+ ASSERT_TRUE (stream_tester .on_h2_remote_end_stream_invoked );
6185+ ASSERT_FALSE (stream_tester .complete );
6186+
6187+ /* Now let client finish sending */
6188+ aws_input_stream_tester_set_max_bytes_per_read (body_stream , SIZE_MAX );
6189+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6190+
6191+ /* Now on_complete should have fired */
6192+ ASSERT_TRUE (stream_tester .complete );
6193+ ASSERT_INT_EQUALS (AWS_ERROR_SUCCESS , stream_tester .on_complete_error_code );
6194+
6195+ /* clean up */
6196+ aws_http_headers_release (response_headers );
6197+ aws_http_message_release (request );
6198+ aws_input_stream_release (body_stream );
6199+ client_stream_tester_clean_up (& stream_tester );
6200+ return s_tester_clean_up ();
6201+ }
6202+
6203+ /* Test that on_h2_remote_end_stream works with body data */
6204+ TEST_CASE (h2_client_on_h2_remote_end_stream_with_body_data ) {
6205+ ASSERT_SUCCESS (s_tester_init (allocator , ctx ));
6206+
6207+ /* get connection preface and acks out of the way */
6208+ ASSERT_SUCCESS (h2_fake_peer_send_connection_preface_default_settings (& s_tester .peer ));
6209+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6210+
6211+ /* send request */
6212+ struct aws_http_message * request = aws_http2_message_new_request (allocator );
6213+ ASSERT_NOT_NULL (request );
6214+
6215+ struct aws_http_header request_headers_src [] = {
6216+ DEFINE_HEADER (":method" , "GET" ),
6217+ DEFINE_HEADER (":scheme" , "https" ),
6218+ DEFINE_HEADER (":path" , "/" ),
6219+ };
6220+ aws_http_message_add_header_array (request , request_headers_src , AWS_ARRAY_SIZE (request_headers_src ));
6221+
6222+ bool track_on_h2_remote_end_stream = true;
6223+ struct client_stream_tester_options tester_options = {
6224+ .request = request ,
6225+ .connection = s_tester .connection ,
6226+ .on_h2_remote_end_stream = & track_on_h2_remote_end_stream ,
6227+ };
6228+ struct client_stream_tester stream_tester ;
6229+ ASSERT_SUCCESS (client_stream_tester_init (& stream_tester , allocator , & tester_options ));
6230+
6231+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6232+ uint32_t stream_id = aws_http_stream_get_id (stream_tester .stream );
6233+
6234+ /* fake peer sends response headers */
6235+ struct aws_http_header response_headers_src [] = {
6236+ DEFINE_HEADER (":status" , "200" ),
6237+ };
6238+
6239+ struct aws_http_headers * response_headers = aws_http_headers_new (allocator );
6240+ aws_http_headers_add_array (response_headers , response_headers_src , AWS_ARRAY_SIZE (response_headers_src ));
6241+
6242+ struct aws_h2_frame * headers_frame =
6243+ aws_h2_frame_new_headers (allocator , stream_id , response_headers , false /*end_stream*/ , 0 , NULL );
6244+ ASSERT_SUCCESS (h2_fake_peer_send_frame (& s_tester .peer , headers_frame ));
6245+
6246+ /* fake peer sends body data */
6247+ const char * body = "response body" ;
6248+ ASSERT_SUCCESS (h2_fake_peer_send_data_frame_str (& s_tester .peer , stream_id , body , false /*end_stream*/ ));
6249+
6250+ /* fake peer sends final data frame with END_STREAM */
6251+ ASSERT_SUCCESS (h2_fake_peer_send_data_frame_str (& s_tester .peer , stream_id , " more data" , true /*end_stream*/ ));
6252+
6253+ /* validate that both callbacks fired */
6254+ testing_channel_drain_queued_tasks (& s_tester .testing_channel );
6255+ ASSERT_TRUE (stream_tester .on_h2_remote_end_stream_invoked );
6256+ ASSERT_TRUE (stream_tester .complete );
6257+ ASSERT_INT_EQUALS (AWS_ERROR_SUCCESS , stream_tester .on_complete_error_code );
6258+
6259+ /* clean up */
6260+ aws_http_headers_release (response_headers );
6261+ aws_http_message_release (request );
6262+ client_stream_tester_clean_up (& stream_tester );
6263+ return s_tester_clean_up ();
6264+ }
6265+
60286266/* The overflow window update will be capped to the allowed max to be sent. */
60296267TEST_CASE (h2_client_cap_manual_window_update ) {
60306268 /* Automated and default threshold */
0 commit comments