Repository: envoyproxy/envoy
File: source/common/router/router.cc (C++)

Code before:
                               UpstreamRequest& upstream_request, bool end_stream) {
  ENVOY_STREAM_LOG(debug, "upstream headers complete: end_stream={}", *callbacks_, end_stream);

  ASSERT(!host_selection_cancelable_);

  // When grpc-status appears in response headers, convert grpc-status to HTTP status code
  // for outlier detection. This does not currently change any stats or logging and does not
  // handle the case when an error grpc-status is sent as a trailer.
  absl::optional<Grpc::Status::GrpcStatus> grpc_status;
  uint64_t grpc_to_http_status = 0;
  uint64_t put_result_code = response_code;
  if (grpc_request_) {
    grpc_status = Grpc::Common::getGrpcStatus(*headers);
    if (grpc_status.has_value()) {
      grpc_to_http_status = Grpc::Utility::grpcToHttpStatus(grpc_status.value());
      put_result_code = grpc_to_http_status;
    }
  } else {
    // Check cluster's http_protocol_options if different code should be reported to
    // outlier detector.
    absl::optional<bool> matched = cluster_->processHttpForOutlierDetection(*headers);
    if (matched.has_value()) {
      // Outlier detector distinguishes only two values:
      // Anything >= 500 is error.
      // Anything < 500 is success.
      put_result_code = matched.value() ? 500 : 200;
    }
  }

  maybeProcessOrcaLoadReport(*headers, upstream_request);

  upstream_request.upstreamHost()->outlierDetector().putResult(
      put_result_code >= 500 ? Upstream::Outlier::Result::ExtOriginRequestFailed
                             : Upstream::Outlier::Result::ExtOriginRequestSuccess,
      put_result_code);

  if (headers->EnvoyImmediateHealthCheckFail() != nullptr) {
    upstream_request.upstreamHost()->healthChecker().setUnhealthy(
        Upstream::HealthCheckHostMonitor::UnhealthyType::ImmediateHealthCheckFail);
  }

  bool could_not_retry = false;

  // Check if this upstream request was already retried, for instance after
  // hitting a per try timeout. Don't retry it if we already have.
  if (retry_state_) {
    if (upstream_request.retried()) {
      // We already retried this request (presumably for a per try timeout) so
      // we definitely won't retry it again. Check if we would have retried it
      // if we could.
      bool retry_as_early_data; // Not going to be used as we are not retrying.

Review comment (bug):
This change will finally break the `consecutive_gateway_failure` which only consume 502, 503, 504. We may only let the new monitor to consumer the matched result.

Code after:
  } else {
    upstream_request.upstreamHost()->stats().rq_success_.inc();
  }
}

void Filter::onUpstream1xxHeaders(Http::ResponseHeaderMapPtr&& headers,
                                  UpstreamRequest& upstream_request) {
  const uint64_t response_code = Http::Utility::getResponseStatus(*headers);
  chargeUpstreamCode(response_code, *headers, upstream_request.upstreamHost(), false);
  ENVOY_STREAM_LOG(debug, "upstream 1xx ({}).", *callbacks_, response_code);

  downstream_response_started_ = true;
  final_upstream_request_ = &upstream_request;
  resetOtherUpstreams(upstream_request);

  // Don't send retries after 100-Continue has been sent on. Arguably we could attempt to do a
  // retry, assume the next upstream would also send an 100-Continue and swallow the second one
  // but it's sketchy (as the subsequent upstream might not send a 100-Continue) and not worth
  // the complexity until someone asks for it.
  retry_state_.reset();

  callbacks_->encode1xxHeaders(std::move(headers));
}

void Filter::resetAll() {
  while (!upstream_requests_.empty()) {
    auto request_ptr = upstream_requests_.back()->removeFromList(upstream_requests_);
    request_ptr->resetStream();
    callbacks_->dispatcher().deferredDelete(std::move(request_ptr));
  }
}

void Filter::resetOtherUpstreams(UpstreamRequest& upstream_request) {
  // Pop each upstream request on the list and reset it if it's not the one
  // provided. At the end we'll move it back into the list.
  UpstreamRequestPtr final_upstream_request;
  while (!upstream_requests_.empty()) {
    UpstreamRequestPtr upstream_request_tmp =
        upstream_requests_.back()->removeFromList(upstream_requests_);
    if (upstream_request_tmp.get() != &upstream_request) {
      upstream_request_tmp->resetStream();
      // TODO: per-host stat for hedge abandoned.
      // TODO: cluster stat for hedge abandoned.
    } else {
      final_upstream_request = std::move(upstream_request_tmp);
    }
  }

  ASSERT(final_upstream_request);
  // Now put the final request back on this list.
  LinkedList::moveIntoList(std::move(final_upstream_request), upstream_requests_);