Repository: envoyproxy/envoy
File: source/extensions/filters/http/ext_proc/ext_proc.cc (C++)

Code before:
    }
  } else {
    // Any other error results in an immediate response with an error message.
    // This could happen, for example, after a header mutation is rejected.
    stats_.stream_msgs_received_.inc();
    handleErrorResponse(processing_status);
  }

  // Close the gRPC stream if no more external processing needed.
  closeGrpcStreamIfLastRespReceived(*response, is_last_body_resp);
}

void Filter::onGrpcError(Grpc::Status::GrpcStatus status, const std::string& message) {
  ENVOY_STREAM_LOG(warn, "Received gRPC error on stream: {}, message {}", *decoder_callbacks_,
                   status, message);
  stats_.streams_failed_.inc();

  if (processing_complete_) {
    return;
  }

  stats_.server_half_closed_.inc();
  if (failureModeAllow()) {
    onGrpcCloseWithStatus(status);
    stats_.failure_mode_allowed_.inc();
    logging_info_->setFailedOpen();
  } else {
    processing_complete_ = true;
    // Since the stream failed, there is no need to handle timeouts, so
    // make sure that they do not fire now.
    onFinishProcessorCalls(status);
    closeStream();
    ImmediateResponse errorResponse;
    errorResponse.mutable_status()->set_code(
        static_cast<StatusCode>(static_cast<uint32_t>(config_->statusOnError())));
    errorResponse.set_details(
        absl::StrFormat("%s_gRPC_error_%i{%s}", ErrorPrefix, status, message));
    sendImmediateResponse(errorResponse);
  }
}

void Filter::onGrpcClose() { onGrpcCloseWithStatus(Grpc::Status::Aborted); }

void Filter::onGrpcCloseWithStatus(Grpc::Status::GrpcStatus status) {
  ENVOY_STREAM_LOG(debug, "Received gRPC stream close", *decoder_callbacks_);

  if (processing_complete_) {
    return;
  }

  processing_complete_ = true;

Review comment (bug):
Why is the setting the flag in the `logging_info_` (which by the name I assume is only used for logging), is disconnected from the stats update (above)? Or maybe, why is the logging the failed-open state depends on whether `failureModeAllow()` is true or not?
Doesn't it make sense to update the stats and the logging_info struct together?

Code after:
  ENVOY_STREAM_LOG(debug, "Received {} response", *decoder_callbacks_,
                   responseCaseToString(response->response_case()));

  bool is_last_body_resp = false;
  absl::Status processing_status;
  switch (response->response_case()) {
  case ProcessingResponse::ResponseCase::kRequestHeaders:
    setDecoderDynamicMetadata(*response);
    processing_status = decoding_state_.handleHeadersResponse(response->request_headers());
    break;
  case ProcessingResponse::ResponseCase::kResponseHeaders:
    setEncoderDynamicMetadata(*response);
    processing_status = encoding_state_.handleHeadersResponse(response->response_headers());
    break;
  case ProcessingResponse::ResponseCase::kRequestBody:
    is_last_body_resp = isLastBodyResponse(decoding_state_, response->request_body());
    setDecoderDynamicMetadata(*response);
    processing_status = decoding_state_.handleBodyResponse(response->request_body());
    break;
  case ProcessingResponse::ResponseCase::kResponseBody:
    is_last_body_resp = isLastBodyResponse(encoding_state_, response->response_body());
    setEncoderDynamicMetadata(*response);
    processing_status = encoding_state_.handleBodyResponse(response->response_body());
    break;
  case ProcessingResponse::ResponseCase::kRequestTrailers:
    setDecoderDynamicMetadata(*response);
    processing_status = decoding_state_.handleTrailersResponse(response->request_trailers());
    break;
  case ProcessingResponse::ResponseCase::kResponseTrailers:
    setEncoderDynamicMetadata(*response);
    processing_status = encoding_state_.handleTrailersResponse(response->response_trailers());
    break;
  case ProcessingResponse::ResponseCase::kImmediateResponse:
    if (config_->disableImmediateResponse()) {
      ENVOY_STREAM_LOG(debug, "Filter has disable_immediate_response configured. ",
                       *decoder_callbacks_,
                       "Treat the immediate response message as spurious response.");
      processing_status =
          absl::FailedPreconditionError("unhandled immediate response due to config disabled it");
    } else {
      setDecoderDynamicMetadata(*response);
      // We won't be sending anything more to the stream after we
      // receive this message.
      ENVOY_STREAM_LOG(debug, "Sending immediate response", *decoder_callbacks_);
      processing_complete_ = true;
      onFinishProcessorCalls(Grpc::Status::Ok);
      closeStreamMaybeGraceful();
      if (on_processing_response_) {
        on_processing_response_->afterReceivingImmediateResponse(
            response->immediate_response(), absl::OkStatus(), decoder_callbacks_->streamInfo());
      }