@@ -245,9 +245,17 @@ void OnDemandRouteUpdate::onRouteConfigUpdateCompletion(bool route_exists) {
245245 return ;
246246 }
247247
248- if (route_exists && // route can be resolved after an on-demand
249- // VHDS update
250- downstream_end_stream_ && // Redirects require fully read body.
248+ bool can_recreate_stream = false ;
249+ if (Runtime::runtimeFeatureEnabled (" envoy.reloadable_features.on_demand_track_end_stream" )) {
250+ // New behavior: track end_stream state to support stream recreation with fully read bodies.
251+ can_recreate_stream = downstream_end_stream_;
252+ } else {
253+ // Old behavior: reject all requests with bodies.
254+ can_recreate_stream = !callbacks_->decodingBuffer ();
255+ }
256+ if (route_exists && // route can be resolved after an on-demand
257+ // VHDS update
258+ can_recreate_stream && // Redirects require fully read body.
251259 callbacks_->recreateStream (/* headers=*/ nullptr )) {
252260 return ;
253261 }
@@ -261,8 +269,16 @@ void OnDemandRouteUpdate::onClusterDiscoveryCompletion(
261269 Upstream::ClusterDiscoveryStatus cluster_status) {
262270 filter_iteration_state_ = Http::FilterHeadersStatus::Continue;
263271 cluster_discovery_handle_.reset ();
272+ bool can_recreate_stream = false ;
273+ if (Runtime::runtimeFeatureEnabled (" envoy.reloadable_features.on_demand_track_end_stream" )) {
274+ // New behavior: track end_stream state to support stream recreation with fully read bodies.
275+ can_recreate_stream = downstream_end_stream_;
276+ } else {
277+ // Old behavior: reject all requests with bodies.
278+ can_recreate_stream = !callbacks_->decodingBuffer ();
279+ }
264280 if (cluster_status == Upstream::ClusterDiscoveryStatus::Available &&
265- downstream_end_stream_ ) { // Redirects require fully read body.
281+ can_recreate_stream ) { // Redirects require fully read body.
266282 const Http::ResponseHeaderMap* headers = nullptr ;
267283 if (callbacks_->recreateStream (headers)) {
268284 callbacks_->downstreamCallbacks ()->clearRouteCache ();
0 commit comments