@@ -245,9 +245,18 @@ void OnDemandRouteUpdate::onRouteConfigUpdateCompletion(bool route_exists) {
245245 return ;
246246 }
247247
248+ bool can_recreate_stream = false ;
249+ if (Runtime::runtimeFeatureEnabled (
250+ " envoy.reloadable_features.on_demand_track_end_stream" )) {
251+ // New behavior: track end_stream state to support stream recreation with fully read bodies.
252+ can_recreate_stream = downstream_end_stream_;
253+ } else {
254+ // Old behavior: reject all requests with bodies.
255+ can_recreate_stream = !callbacks_->decodingBuffer ();
256+ }
248257 if (route_exists && // route can be resolved after an on-demand
249258 // VHDS update
250- downstream_end_stream_ && // Redirects require fully read body.
259+ can_recreate_stream && // Redirects require fully read body.
251260 callbacks_->recreateStream (/* headers=*/ nullptr )) {
252261 return ;
253262 }
@@ -261,8 +270,17 @@ void OnDemandRouteUpdate::onClusterDiscoveryCompletion(
261270 Upstream::ClusterDiscoveryStatus cluster_status) {
262271 filter_iteration_state_ = Http::FilterHeadersStatus::Continue;
263272 cluster_discovery_handle_.reset ();
273+ bool can_recreate_stream = false ;
274+ if (Runtime::runtimeFeatureEnabled (
275+ " envoy.reloadable_features.on_demand_track_end_stream" )) {
276+ // New behavior: track end_stream state to support stream recreation with fully read bodies.
277+ can_recreate_stream = downstream_end_stream_;
278+ } else {
279+ // Old behavior: reject all requests with bodies.
280+ can_recreate_stream = !callbacks_->decodingBuffer ();
281+ }
264282 if (cluster_status == Upstream::ClusterDiscoveryStatus::Available &&
265- downstream_end_stream_ ) { // Redirects require fully read body.
283+ can_recreate_stream ) { // Redirects require fully read body.
266284 const Http::ResponseHeaderMap* headers = nullptr ;
267285 if (callbacks_->recreateStream (headers)) {
268286 callbacks_->downstreamCallbacks ()->clearRouteCache ();
0 commit comments