bool Filter::setupRedirect(const Http::ResponseHeaderMap& headers,
                           UpstreamRequest& upstream_request) {
  ENVOY_STREAM_LOG(debug, "attempting internal redirect", *callbacks_);
  const Http::HeaderEntry* location = headers.Location();

  // If the internal redirect succeeds, callbacks_->recreateStream() will result in the
  // destruction of this filter before the stream is marked as complete, and onDestroy will reset
  // the stream.
  //
  // Normally when a stream is complete we signal this by resetting the upstream but this cannot
  // be done in this case because if recreateStream fails, the "failure" path continues to call
  // code in onUpstreamHeaders which requires the upstream *not* be reset. To avoid onDestroy
  // performing a spurious stream reset in the case recreateStream() succeeds, we explicitly track
  // stream completion here and check it in onDestroy. This is annoyingly complicated but is
  // better than needlessly resetting streams.
  attempting_internal_redirect_with_complete_stream_ =
      upstream_request.upstreamTiming().last_upstream_rx_byte_received_ && downstream_end_stream_;

  const uint64_t status_code = Http::Utility::getResponseStatus(headers);

  // Redirects are not supported for streaming requests yet.
  if (downstream_end_stream_ &&
      ((internal_redirects_with_body_enabled_ && !request_buffer_overflowed_) ||
       !callbacks_->decodingBuffer()) &&
      location != nullptr &&
      convertRequestHeadersForInternalRedirect(*downstream_headers_, *location, status_code) &&
      callbacks_->recreateStream(&headers)) {
    cluster_->stats().upstream_internal_redirect_succeeded_total_.inc();
    return true;
  }

  attempting_internal_redirect_with_complete_stream_ = false;

  ENVOY_STREAM_LOG(debug, "Internal redirect failed", *callbacks_);
  cluster_->stats().upstream_internal_redirect_failed_total_.inc();
  return false;
}
bool Filter::setupRedirect(const Http::ResponseHeaderMap& headers,
                           UpstreamRequest& upstream_request) {
  ENVOY_STREAM_LOG(debug, "attempting internal redirect", *callbacks_);
  const Http::HeaderEntry* location = headers.Location();

   
   
   
   
   
   
   
   
   
   
  attempting_internal_redirect_with_complete_stream_ =
      upstream_request.upstreamTiming().last_upstream_rx_byte_received_ && downstream_end_stream_;

  const uint64_t status_code = Http::Utility::getResponseStatus(headers);

   
  if (downstream_end_stream_ &&
      ((internal_redirects_with_body_enabled_ && !request_buffer_overflowed_) ||
       !callbacks_->decodingBuffer()) &&
      location != nullptr &&
      convertRequestHeadersForInternalRedirect(*downstream_headers_, *location, status_code) &&
      callbacks_->recreateStream(&headers)) {
    cluster_->stats().upstream_internal_redirect_succeeded_total_.inc();
    return true;
  }

  attempting_internal_redirect_with_complete_stream_ = false;

  ENVOY_STREAM_LOG(debug, "Internal redirect failed", *callbacks_);
  cluster_->stats().upstream_internal_redirect_failed_total_.inc();
  return false;
}