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

Code before:
    // codec but there are no easy answers and this seems simpler.
    auto& stream = *streams_.front();
    stream.response_encoder_->getStream().removeCallbacks(stream);
    if (!stream.response_encoder_->getStream().responseDetails().empty()) {
      stream.filter_manager_.streamInfo().setResponseCodeDetails(
          stream.response_encoder_->getStream().responseDetails());
    } else if (!details.empty()) {
      stream.filter_manager_.streamInfo().setResponseCodeDetails(details);
    }
    if (response_flag.has_value()) {
      stream.filter_manager_.streamInfo().setResponseFlag(response_flag.value());
    }
    stream.onResetStream(StreamResetReason::ConnectionTermination, absl::string_view());
  }
}

void ConnectionManagerImpl::onEvent(Network::ConnectionEvent event) {
  if (event == Network::ConnectionEvent::LocalClose) {
    stats_.named_.downstream_cx_destroy_local_.inc();
  }

  if (event == Network::ConnectionEvent::RemoteClose ||
      event == Network::ConnectionEvent::LocalClose) {
    // Propagate transport failure reason to the connection-level StreamInfo so that
    // it's available for access logging and filters.
    read_callbacks_->connection().streamInfo().setDownstreamTransportFailureReason(
        read_callbacks_->connection().transportFailureReason());

    std::string details;
    if (event == Network::ConnectionEvent::RemoteClose) {
      remote_close_ = true;
      stats_.named_.downstream_cx_destroy_remote_.inc();
      details = StreamInfo::ResponseCodeDetails::get().DownstreamRemoteDisconnect;
    } else {
      absl::string_view local_close_reason = read_callbacks_->connection().localCloseReason();
      ENVOY_BUG(!local_close_reason.empty(), "Local Close Reason was not set!");
      details = fmt::format(
          fmt::runtime(StreamInfo::ResponseCodeDetails::get().DownstreamLocalDisconnect),
          StringUtil::replaceAllEmptySpace(local_close_reason));
    }

    // TODO(mattklein123): It is technically possible that something outside of the filter causes
    // a local connection close, so we still guard against that here. A better solution would be to
    // have some type of "pre-close" callback that we could hook for cleanup that would get called
    // regardless of where local close is invoked from.
    // NOTE: that this will cause doConnectionClose() to get called twice in the common local close
    // cases, but the method protects against that.
    // NOTE: In the case where a local close comes from outside the filter, this will cause any
    // stream closures to increment remote close stats. We should do better here in the future,
    // via the pre-close callback mentioned above.
    doConnectionClose(absl::nullopt, StreamInfo::CoreResponseFlag::DownstreamConnectionTermination,

Review comment (bug):
This does't seem the right place. The current `setDownstreamTransportFailureReason` is at the `ActiveTcpConnection` level [here](https://github.com/envoyproxy/envoy/blob/6adf830601de3665d4cb5b2625efc7fa31d992db/source/common/listener_manager/active_stream_listener_base.cc#L118), and the close event from that callback is the last one when a connection is closing. Originally it works well since the tls failure info is intended to work with the listener level access logger, which happens during the destruction of `ActiveTcpConnection`. 

Then I assume from the issue they reported, they added the stats during the onEvent callback of the WASM network filter that is before HCM.  The feature of adding to CEL `connection.transport_failure_reason` was broken, and the real fix is to probably move the `setDownstreamTransportFailureReason` forward to `closeSocket`. 

Code after:
    // codec but there are no easy answers and this seems simpler.
    auto& stream = *streams_.front();
    stream.response_encoder_->getStream().removeCallbacks(stream);
    if (!stream.response_encoder_->getStream().responseDetails().empty()) {
      stream.filter_manager_.streamInfo().setResponseCodeDetails(
          stream.response_encoder_->getStream().responseDetails());
    } else if (!details.empty()) {
      stream.filter_manager_.streamInfo().setResponseCodeDetails(details);
    }
    if (response_flag.has_value()) {
      stream.filter_manager_.streamInfo().setResponseFlag(response_flag.value());
    }
    stream.onResetStream(StreamResetReason::ConnectionTermination, absl::string_view());
  }
}

void ConnectionManagerImpl::onEvent(Network::ConnectionEvent event) {
  if (event == Network::ConnectionEvent::LocalClose) {
    stats_.named_.downstream_cx_destroy_local_.inc();
  }

  if (event == Network::ConnectionEvent::RemoteClose ||
      event == Network::ConnectionEvent::LocalClose) {

    std::string details;
    if (event == Network::ConnectionEvent::RemoteClose) {
      remote_close_ = true;
      stats_.named_.downstream_cx_destroy_remote_.inc();
      details = StreamInfo::ResponseCodeDetails::get().DownstreamRemoteDisconnect;
    } else {
      absl::string_view local_close_reason = read_callbacks_->connection().localCloseReason();
      ENVOY_BUG(!local_close_reason.empty(), "Local Close Reason was not set!");
      details = fmt::format(
          fmt::runtime(StreamInfo::ResponseCodeDetails::get().DownstreamLocalDisconnect),
          StringUtil::replaceAllEmptySpace(local_close_reason));
    }

    // TODO(mattklein123): It is technically possible that something outside of the filter causes
    // a local connection close, so we still guard against that here. A better solution would be to
    // have some type of "pre-close" callback that we could hook for cleanup that would get called
    // regardless of where local close is invoked from.
    // NOTE: that this will cause doConnectionClose() to get called twice in the common local close
    // cases, but the method protects against that.
    // NOTE: In the case where a local close comes from outside the filter, this will cause any
    // stream closures to increment remote close stats. We should do better here in the future,
    // via the pre-close callback mentioned above.
    doConnectionClose(absl::nullopt, StreamInfo::CoreResponseFlag::DownstreamConnectionTermination,
                      details);
  }
}