#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
{ALL_HTTP_CONN_MAN_STATS(POOL_COUNTER_PREFIX(scope, prefix), POOL_GAUGE_PREFIX(scope, prefix),
ConnectionManagerTracingStats ConnectionManagerImpl::generateTracingStats(const std::string& prefix,
ConnectionManagerImpl::generateListenerStats(const std::string& prefix, Stats::Scope& scope) {
runtime_.snapshot().getInteger(ConnectionManagerImpl::MaxRequestsPerIoCycle, UINT32_MAX)),
void ConnectionManagerImpl::initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) {
dispatcher_->createSchedulableCallback([this]() -> void { onDeferredRequestProcessing(); });
dispatcher_->createScaledTimer(Event::ScaledTimerType::HttpDownstreamIdleConnectionTimeout,
{stats_.named_.downstream_cx_rx_bytes_total_, stats_.named_.downstream_cx_rx_bytes_buffered_,
stats_.named_.downstream_cx_tx_bytes_total_, stats_.named_.downstream_cx_tx_bytes_buffered_,
if (drain_state_ == DrainState::Closing && streams_.empty() && !codec_->wantsToWrite()) {
void ConnectionManagerImpl::doEndStream(ActiveStream& stream, bool check_for_deferred_close) {
// The order of what happens in this routine is important and a little complicated. We first see
// if the stream needs to be reset. If it needs to be, this will end up invoking reset callbacks
// and then moving the stream to the deferred destruction list. If the stream has not been reset,
// we move it to the deferred deletion list here. Then, we potentially close the connection. This
RequestDecoderHandlePtr ConnectionManagerImpl::newStreamHandle(ResponseEncoder& response_encoder,
new_stream->streamInfo().setDownstreamBytesMeter(response_encoder.getStream().bytesMeter());
void ConnectionManagerImpl::handleCodecErrorImpl(absl::string_view error, absl::string_view details,
doConnectionClose(Network::ConnectionCloseType::FlushWriteAndDelay, response_flag, details);
handleCodecErrorImpl(error, absl::StrCat("codec_error:", StringUtil::replaceAllEmptySpace(error)),
codec_ = config_->createCodec(read_callbacks_->connection(), data, *this, overload_manager_);
if (hcm_ondata_creating_codec_ != nullptr && hcm_ondata_creating_codec_->shouldShedLoad()) {
doConnectionClose(absl::nullopt, StreamInfo::CoreResponseFlag::DownstreamConnectionTermination,
const uint64_t lifetime = std::chrono::duration_cast<std::chrono::seconds>(*duration).count();
runtime_.snapshot().getInteger(ConnectionManagerImpl::PrematureResetTotalStreamCountKey, 500);
// - HTTP/2: shutdownNotice() sends GOAWAY with high stream ID, then goAway() sends final GOAWAY
return parent_.connection_manager_.config_->requestIDExtension()->get(*parent_.request_headers_);
connection_manager_tracing_config_(connection_manager_.config_->tracingConfig() == nullptr
connection_manager_.stats_.named_.downstream_rq_time_, connection_manager_.timeSource())),
"Either routeConfigProvider or (scopedRouteConfigProvider and scopeKeyBuilder) should be "
auto factory = Envoy::Config::Utility::getFactoryByName<RouteConfigUpdateRequesterFactory>(
filter_manager_.streamInfo().getDownstreamBytesMeter()->takeDownstreamPeriodicLoggingSnapshot(
filter_manager_.streamInfo().setResponseFlag(StreamInfo::CoreResponseFlag::StreamIdleTimeout);
"downstream duration timeout", nullptr, Grpc::Status::WellKnownGrpcStatus::DeadlineExceeded,
void ConnectionManagerImpl::ActiveStream::chargeStats(const ResponseHeaderMap& headers) {
if (trace_refresh_after_route_refresh_ && connection_manager_tracing_config_.has_value()) {
// No response is sent back downstream for internal redirects, so don't charge downstream stats.
response_code_details == Envoy::StreamInfo::ResponseCodeDetails::get().InternalRedirect) {
if (connection_manager_tracing_config_->operation_name_ == Tracing::OperationName::Egress) {
void ConnectionManagerImpl::ActiveStream::setResponseDecorator(ResponseHeaderMap& headers) {
if (connection_manager_tracing_config_->operation_name_ == Tracing::OperationName::Ingress) {
Code response_code = failure_details == Http1ResponseCodeDetail::get().InvalidTransferEncoding
void ConnectionManagerImpl::ActiveStream::maybeRecordLastByteReceived(bool end_stream) {
ENVOY_STREAM_LOG(debug, "request headers complete (end_stream={}):\n{}", *this, end_stream,
// Both shouldDrainConnectionUponCompletion() and is_head_request_ affect local replies: set them
snapped_route_config_ = connection_manager_.config_->routeConfigProvider()->configCast();
// :path header for CONNECT requests. We expect the codec to have broken the path into pieces if
// applicable. NOTE: Currently the HTTP/1.1 codec only does this when the allow_absolute_url flag
sendLocalReply(Code::NotFound, "The path is incorrect for CONNECT-UDP", nullptr, absl::nullopt,
if (!request_headers_->getPathValue().empty() && request_headers_->getPathValue()[0] != '/') {
ConnectionManagerUtility::maybeNormalizePath(*request_headers_, *connection_manager_.config_);
ASSERT(filter_manager_.streamInfo().downstreamAddressProvider().remoteAddress() != nullptr);
void ConnectionManagerImpl::ActiveStream::decodeData(Buffer::Instance& data, bool end_stream) {
void ConnectionManagerImpl::ActiveStream::decodeTrailers(RequestTrailerMapPtr&& trailers) {
// After going through filters, the ownership of metadata_map will be passed to terminal filter.
// The terminal filter may encode metadata_map to the next hop immediately or store metadata_map
// NOTE: if a RDS subscription hasn't got a RouteConfiguration back, a Router::NullConfigImpl is
void ConnectionManagerImpl::ActiveStream::refreshCachedRoute() { refreshCachedRoute(nullptr); }
std::chrono::milliseconds time_used = std::chrono::duration_cast<std::chrono::milliseconds>(
void ConnectionManagerImpl::ActiveStream::refreshCachedRoute(const Router::RouteCallback& cb) {
absl::optional<Router::ConfigConstSharedPtr> ConnectionManagerImpl::ActiveStream::routeConfig() {
if (code == Http::Code::BadRequest && connection_manager_.codec_->protocol() < Protocol::Http2 &&
void ConnectionManagerImpl::ActiveStream::encode1xxHeaders(ResponseHeaderMap& response_headers) {
ENVOY_STREAM_LOG(debug, "encoding 1xx continue headers via codec:\n{}", *this, response_headers);
(transformation == ConnectionManagerConfig::HttpConnectionManagerProto::APPEND_IF_ABSENT &&
connection_manager_.proxy_name_, connection_manager_.clear_hop_by_hop_response_headers_);
// If we're an inbound listener, then we should drain even if the drain direction is inbound only.
ENVOY_STREAM_LOG(debug, "encoding headers via codec (end_stream={}):\n{}", *this, end_stream,
void ConnectionManagerImpl::ActiveStream::encodeData(Buffer::Instance& data, bool end_stream) {
ENVOY_STREAM_LOG(trace, "encoding data via codec (size={} end_stream={})", *this, data.length(),
void ConnectionManagerImpl::ActiveStream::onDecoderFilterBelowWriteBufferLowWatermark() {
ENVOY_STREAM_LOG(debug, "Read-enabling downstream stream due to filter callbacks.", *this);
void ConnectionManagerImpl::ActiveStream::onDecoderFilterAboveWriteBufferHighWatermark() {
ENVOY_STREAM_LOG(debug, "Read-disabling downstream stream due to filter callbacks.", *this);
const absl::string_view encoder_details = response_encoder_->getStream().responseDetails();
filter_manager_.streamInfo().setResponseFlag(StreamInfo::CoreResponseFlag::OverloadManager);
ENVOY_STREAM_LOG(debug, "Disabling upstream stream due to downstream stream watermark.", *this);
ENVOY_STREAM_LOG(debug, "Enabling upstream stream due to downstream stream watermark.", *this);
const bool http_10_sans_cl = (connection_manager_.codec_->protocol() == Protocol::Http10) &&
const bool connection_close = filter_manager_.streamInfo().shouldDrainConnectionUponCompletion();
// We must check if the 'cached_route_' optional is populated since this function can be called
OptRef<const Tracing::Config> ConnectionManagerImpl::ActiveStream::tracingConfig() const {
const ScopeTrackedObject& ConnectionManagerImpl::ActiveStream::scope() { return *this; }
* cached_route_/cached_cluster_info_ ActiveStream attributes, the FilterManager streamInfo, tracing
} else if (!has_explicit_global_flush_timeout_ && route_entry->idleTimeout().has_value()) {
const bool proxy_body = buffered_request_data != nullptr && buffered_request_data->length() > 0;
// have already been called at this point, the encoder still needs the new decoder for deferred
// store any objects with a LifeSpan at or above DownstreamRequest. This is to avoid unnecessary
Http1StreamEncoderOptionsOptRef ConnectionManagerImpl::ActiveStream::http1StreamEncoderOptions() {
void ConnectionManagerImpl::ActiveStream::resetStream(Http::StreamResetReason, absl::string_view) {
// Move the iterator to the previous item in case the `onDeferredRequestProcessing` call removes