@@ -3240,45 +3240,6 @@ TEST_F(RouterTest, RetryRequestDuringBodyBufferLimitExceeded) {
32403240 EXPECT_CALL (callbacks_, decodingBuffer ()).WillRepeatedly (Return (&decoding_buffer));
32413241 EXPECT_CALL (callbacks_, addDecodedData (_, true ))
32423242 .WillRepeatedly (Invoke ([&](Buffer::Instance& data, bool ) { decoding_buffer.move (data); }));
3243- EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillOnce (Return (10 ));
3244-
3245- NiceMock<Http::MockRequestEncoder> encoder1;
3246- Http::ResponseDecoder* response_decoder = nullptr ;
3247- expectNewStreamWithImmediateEncoder (encoder1, &response_decoder, Http::Protocol::Http10);
3248-
3249- Http::TestRequestHeaderMapImpl headers{
3250- {" x-envoy-retry-on" , " 5xx" }, {" x-envoy-internal" , " true" }, {" myheader" , " present" }};
3251- HttpTestUtility::addDefaultHeaders (headers);
3252- router_->decodeHeaders (headers, false );
3253- const std::string body1 (" body1" );
3254- Buffer::OwnedImpl buf1 (body1);
3255- EXPECT_CALL (*router_->retry_state_ , enabled ()).Times (2 ).WillRepeatedly (Return (true ));
3256- router_->decodeData (buf1, false );
3257-
3258- router_->retry_state_ ->expectResetRetry ();
3259- encoder1.stream_ .resetStream (Http::StreamResetReason::RemoteReset);
3260-
3261- // Send additional 15 bytes - total 55 bytes, which should exceed request body buffer limit (50).
3262- const std::string body2 (15 , ' y' );
3263- Buffer::OwnedImpl buf2 (body2);
3264- router_->decodeData (buf2, false );
3265-
3266- EXPECT_EQ (callbacks_.details (), " request_payload_exceeded_retry_buffer_limit" );
3267- EXPECT_EQ (1U , cm_.thread_local_cluster_ .cluster_ .info_ ->stats_store_
3268- .counter (" retry_or_shadow_abandoned" )
3269- .value ());
3270- EXPECT_TRUE (verifyHostUpstreamStats (0 , 1 ));
3271- }
3272-
3273- // Test that router uses request_body_buffer_limit when configured instead of
3274- // per_request_buffer_limit.
3275- TEST_F (RouterTest, RequestBodyBufferLimitExceeded) {
3276- Buffer::OwnedImpl decoding_buffer;
3277- EXPECT_CALL (callbacks_, decodingBuffer ()).WillRepeatedly (Return (&decoding_buffer));
3278- EXPECT_CALL (callbacks_, addDecodedData (_, true ))
3279- .WillRepeatedly (Invoke ([&](Buffer::Instance& data, bool ) { decoding_buffer.move (data); }));
3280- // Configure a large request body buffer limit (50 bytes) but small request buffer limit (10
3281- // bytes).
32823243 EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillOnce (Return (50 ));
32833244
32843245 NiceMock<Http::MockRequestEncoder> encoder1;
@@ -3290,7 +3251,7 @@ TEST_F(RouterTest, RequestBodyBufferLimitExceeded) {
32903251 HttpTestUtility::addDefaultHeaders (headers);
32913252 router_->decodeHeaders (headers, false );
32923253
3293- // Send 40 bytes - should be within request body buffer limit (50) but exceeds retry limit (10) .
3254+ // Send 40 bytes - should be within request body buffer limit (50).
32943255 const std::string body1 (40 , ' x' );
32953256 Buffer::OwnedImpl buf1 (body1);
32963257 EXPECT_CALL (*router_->retry_state_ , enabled ()).Times (2 ).WillRepeatedly (Return (true ));
@@ -3319,8 +3280,7 @@ TEST_F(RouterTest, BufferLimitLogicCase1RequestBodyBufferLimitSet) {
33193280 EXPECT_CALL (callbacks_, addDecodedData (_, true ))
33203281 .WillRepeatedly (Invoke ([&](Buffer::Instance& data, bool ) { decoding_buffer.move (data); }));
33213282
3322- // Case 1: request_body_buffer_limit=60, per_request_buffer_limit_bytes=20
3323- // Should use request_body_buffer_limit = 60
3283+ // Use route level buffer limit.
33243284 EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillRepeatedly (Return (60 ));
33253285
33263286 NiceMock<Http::MockRequestEncoder> encoder1;
@@ -3353,8 +3313,7 @@ TEST_F(RouterTest, BufferLimitLogicCase1RequestBodyBufferLimitSet) {
33533313 EXPECT_TRUE (verifyHostUpstreamStats (0 , 1 ));
33543314}
33553315
3356- // When per_request_buffer_limit_bytes is set but request_body_buffer_limit is not set,
3357- // we should use min(per_request_buffer_limit_bytes, per_connection_buffer_limit_bytes).
3316+ // Route level request buffer limit will override the connection buffer limit.
33583317TEST_F (RouterTest, BufferLimitLogicCase2PerRequestSetRequestBodyNotSet) {
33593318 Buffer::OwnedImpl decoding_buffer;
33603319 EXPECT_CALL (callbacks_, decodingBuffer ()).WillRepeatedly (Return (&decoding_buffer));
@@ -3363,8 +3322,8 @@ TEST_F(RouterTest, BufferLimitLogicCase2PerRequestSetRequestBodyNotSet) {
33633322 // Set up the connection buffer limit mock to return 40 as expected
33643323 EXPECT_CALL (callbacks_, bufferLimit ()).WillRepeatedly (Return (40 ));
33653324
3366- // Case 2: per_request_buffer_limit_bytes= 20, request_body_buffer_limit=not set
3367- // Should use min(20, connection_buffer_limit) = 20 (since connection limit is default 40)
3325+ // Route level request buffer limit is set to 20, which should override connection buffer limit
3326+ // of 40.
33683327 EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillRepeatedly (Return (20 ));
33693328
33703329 NiceMock<Http::MockRequestEncoder> encoder1;
@@ -3397,51 +3356,6 @@ TEST_F(RouterTest, BufferLimitLogicCase2PerRequestSetRequestBodyNotSet) {
33973356 EXPECT_TRUE (verifyHostUpstreamStats (0 , 1 ));
33983357}
33993358
3400- // Test that when connection limit is smaller than per_request limit,
3401- // we use min(per_request_buffer_limit_bytes, per_connection_buffer_limit_bytes) = connection limit.
3402- TEST_F (RouterTest, BufferLimitLogicCase2ConnectionLimitSmaller) {
3403- Buffer::OwnedImpl decoding_buffer;
3404- EXPECT_CALL (callbacks_, decodingBuffer ()).WillRepeatedly (Return (&decoding_buffer));
3405- EXPECT_CALL (callbacks_, addDecodedData (_, true ))
3406- .WillRepeatedly (Invoke ([&](Buffer::Instance& data, bool ) { decoding_buffer.move (data); }));
3407- // Set up the connection buffer limit mock to return 40 as expected
3408- EXPECT_CALL (callbacks_, bufferLimit ()).WillRepeatedly (Return (40 ));
3409-
3410- // Case 2: per_request_buffer_limit_bytes=50, request_body_buffer_limit=not set
3411- // Should use min(50, connection_limit) = min(50, 40) = 40
3412- // With consolidated approach, the effective limit should be 40
3413- EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillRepeatedly (Return (40 ));
3414-
3415- NiceMock<Http::MockRequestEncoder> encoder1;
3416- Http::ResponseDecoder* response_decoder = nullptr ;
3417- expectNewStreamWithImmediateEncoder (encoder1, &response_decoder, Http::Protocol::Http10);
3418-
3419- Http::TestRequestHeaderMapImpl headers{{" x-envoy-retry-on" , " 5xx" }, {" x-envoy-internal" , " true" }};
3420- HttpTestUtility::addDefaultHeaders (headers);
3421- router_->decodeHeaders (headers, false );
3422-
3423- // Send initial data (35 bytes)
3424- const std::string body1 (35 , ' x' );
3425- Buffer::OwnedImpl buf1 (body1);
3426- EXPECT_CALL (*router_->retry_state_ , enabled ()).Times (2 ).WillRepeatedly (Return (true ));
3427- router_->decodeData (buf1, false );
3428-
3429- // Simulate upstream failure to trigger retry logic
3430- router_->retry_state_ ->expectResetRetry ();
3431- encoder1.stream_ .resetStream (Http::StreamResetReason::RemoteReset);
3432-
3433- // Send additional data (10 bytes) - total 45 bytes should exceed connection limit of 40
3434- const std::string body2 (10 , ' y' );
3435- Buffer::OwnedImpl buf2 (body2);
3436- router_->decodeData (buf2, false );
3437-
3438- EXPECT_EQ (callbacks_.details (), " request_payload_exceeded_retry_buffer_limit" );
3439- EXPECT_EQ (1U , cm_.thread_local_cluster_ .cluster_ .info_ ->stats_store_
3440- .counter (" retry_or_shadow_abandoned" )
3441- .value ());
3442- EXPECT_TRUE (verifyHostUpstreamStats (0 , 1 ));
3443- }
3444-
34453359// Test that when neither fields are set we use per_connection_buffer_limit_bytes.
34463360TEST_F (RouterTest, BufferLimitLogicCase3NeitherFieldSet) {
34473361 Buffer::OwnedImpl decoding_buffer;
@@ -4097,9 +4011,54 @@ TEST_F(RouterTest, NoRetryWithBodyLimit) {
40974011 EXPECT_CALL (callbacks_, addDecodedData (_, _)).Times (0 );
40984012 Buffer::OwnedImpl body (" t" );
40994013 router_->decodeData (body, false );
4014+ Buffer::OwnedImpl body2 (" t" );
4015+ // Ensure subsequent chunks after overflow are also not buffered.
4016+ router_->decodeData (body2, false );
41004017 EXPECT_EQ (1U ,
41014018 callbacks_.route_ ->virtual_host_ ->virtual_cluster_ .stats ().upstream_rq_total_ .value ());
41024019
4020+ EXPECT_EQ (1U , cm_.thread_local_cluster_ .cluster_ .info_ ->stats_store_
4021+ .counter (" retry_or_shadow_abandoned" )
4022+ .value ());
4023+
4024+ Http::ResponseHeaderMapPtr response_headers (
4025+ new Http::TestResponseHeaderMapImpl{{" :status" , " 200" }});
4026+ response_decoder->decodeHeaders (std::move (response_headers), true );
4027+ }
4028+
4029+ TEST_F (RouterTest, EnableRedirectAndRetryButNoRetryWithBodyLimit) {
4030+ TestScopedRuntime scoped_runtime;
4031+ scoped_runtime.mergeValues (
4032+ {{" envoy.reloadable_features.allow_multiplexed_upstream_half_close" , " false" }});
4033+
4034+ recreateFilter ();
4035+ NiceMock<Http::MockRequestEncoder> encoder1;
4036+ Http::ResponseDecoder* response_decoder = nullptr ;
4037+ expectNewStreamWithImmediateEncoder (encoder1, &response_decoder, Http::Protocol::Http10);
4038+
4039+ // Enable redirects also. This feature will not be used but will affect buffer logic.
4040+ enableRedirects (3 );
4041+
4042+ // Set a per route body limit which disallows any buffering.
4043+ EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillOnce (Return (0 ));
4044+ Http::TestRequestHeaderMapImpl headers{{" x-envoy-retry-on" , " 5xx" }, {" x-envoy-internal" , " true" }};
4045+ HttpTestUtility::addDefaultHeaders (headers);
4046+ router_->decodeHeaders (headers, false );
4047+ // Unlike RetryUpstreamReset above the data won't be buffered as the body exceeds the buffer limit
4048+ EXPECT_CALL (*router_->retry_state_ , enabled ()).WillOnce (Return (true ));
4049+ EXPECT_CALL (callbacks_, addDecodedData (_, _)).Times (0 );
4050+ Buffer::OwnedImpl body (" t" );
4051+ router_->decodeData (body, false );
4052+ Buffer::OwnedImpl body2 (" t" );
4053+ // Ensure subsequent chunks after overflow are also not buffered.
4054+ router_->decodeData (body2, false );
4055+ EXPECT_EQ (1U ,
4056+ callbacks_.route_ ->virtual_host_ ->virtual_cluster_ .stats ().upstream_rq_total_ .value ());
4057+
4058+ EXPECT_EQ (1U , cm_.thread_local_cluster_ .cluster_ .info_ ->stats_store_
4059+ .counter (" retry_or_shadow_abandoned" )
4060+ .value ());
4061+
41034062 Http::ResponseHeaderMapPtr response_headers (
41044063 new Http::TestResponseHeaderMapImpl{{" :status" , " 200" }});
41054064 response_decoder->decodeHeaders (std::move (response_headers), true );
@@ -5067,6 +5026,41 @@ TEST_F(RouterTest, InternalRedirectAcceptedWithRequestBody) {
50675026 ->value ());
50685027}
50695028
5029+ TEST_F (RouterTest, InternalRedirectWithRequestBodyBufferOverflow) {
5030+ EXPECT_CALL (callbacks_.route_ ->route_entry_ , requestBodyBufferLimit ()).WillOnce (Return (10 ));
5031+
5032+ enableRedirects ();
5033+ sendRequest (false );
5034+
5035+ EXPECT_CALL (callbacks_.dispatcher_ , createTimer_);
5036+
5037+ Buffer::InstancePtr body_data (new Buffer::OwnedImpl (" random_fake_data" ));
5038+ // We will not buffer the body data because it exceeds the buffer limit. But note the initial
5039+ // request is still valid.
5040+ EXPECT_CALL (callbacks_, addDecodedData (_, _)).Times (0 );
5041+ EXPECT_EQ (Http::FilterDataStatus::StopIterationNoBuffer, router_->decodeData (*body_data, true ));
5042+
5043+ // No redirect because buffer overflowed.
5044+ EXPECT_CALL (callbacks_.route_ ->route_entry_ .internal_redirect_policy_ , responseHeadersToCopy ())
5045+ .Times (0 );
5046+ EXPECT_CALL (callbacks_.downstream_callbacks_ , clearRouteCache ()).Times (0 );
5047+ EXPECT_CALL (callbacks_, recreateStream (_)).Times (0 );
5048+
5049+ response_decoder_->decodeHeaders (std::move (redirect_headers_), false );
5050+ Buffer::OwnedImpl response_data (" 1234567890" );
5051+ response_decoder_->decodeData (response_data, false );
5052+
5053+ router_->onDestroy ();
5054+ EXPECT_FALSE (callbacks_.streamInfo ().filterState ()->hasDataWithName (" num_internal_redirects" ));
5055+
5056+ EXPECT_EQ (1U , cm_.thread_local_cluster_ .cluster_ .info_ ->stats_store_
5057+ .counter (" retry_or_shadow_abandoned" )
5058+ .value ());
5059+ EXPECT_EQ (1U , cm_.thread_local_cluster_ .cluster_ .info_ ->stats_store_
5060+ .counter (" upstream_internal_redirect_failed_total" )
5061+ .value ());
5062+ }
5063+
50705064TEST_F (RouterTest, CrossSchemeRedirectRejectedByPolicy) {
50715065 enableRedirects ();
50725066 sendRequest ();
0 commit comments