HTTP Connection Manager

HTTP Connection Manager Deep-Dive

What This Component Does

The HTTP Connection Manager (HCM) is Envoy’s most critical network filter. It bridges the gap between raw TCP bytes (downstream connections) and HTTP-level request/response processing. The HCM manages HTTP codec instantiation (HTTP/1.1, HTTP/2, HTTP/3), creates per-request streams, drives the HTTP filter chain, handles route configuration (from RDS or inline), manages access logging, integrates distributed tracing, and coordinates timeouts/idle management.

Every HTTP request processed by Envoy passes through the HCM. It is configured as a network filter (type envoy.filters.network.http_connection_manager) in listener filter chains and is the terminal filter for most HTTP-serving listeners.

Use cases: Any listener handling HTTP traffic uses the HCM. It is the core component for API gateways, service mesh sidecars, gRPC proxying, and HTTP reverse proxies. The HCM is always enabled for HTTP listeners; you configure it via the HttpConnectionManager protobuf message in bootstrap or LDS.

How It Works

The HCM receives raw bytes from the network filter chain via the onData() callback, feeds them into an HTTP codec, and dispatches decoded requests through a configurable chain of HTTP filters (authentication, rate limiting, routing, etc.). Each HTTP request creates an ActiveStream that tracks its lifecycle from headers to trailers.

Internal Flow Diagram

flowchart TD
    A[Network::ReadFilter::onData()<br/>Raw bytes from downstream] --> B[HTTP Codec<br/>HTTP/1.1: http-parser<br/>HTTP/2: nghttp2<br/>HTTP/3: quiche]
    B --> C[onMessageBegin / onHeaders<br/>Create ActiveStream]
    C --> D[ActiveStream::decodeHeaders()<br/>Traverse HTTP filter chain]
    D --> E{Filter returns?}
    E -->|Continue| F[Next filter in chain]
    E -->|StopIteration| G[Pause chain<br/>Await continueDecoding()]
    F --> H[Router Filter<br/>Terminal filter]
    H --> I[Route Table Match<br/>RDS or inline routes]
    I --> J[Select cluster + upstream<br/>Via ClusterManager]
    J --> K[Upstream request<br/>Connection pool]
    K --> L[Upstream response]
    L --> M[ActiveStream::encodeHeaders()<br/>Reverse filter chain]
    M --> N[HTTP Codec encode<br/>Serialize response]
    N --> O[Write to downstream<br/>connection]
    O --> P[Access Log<br/>After response complete]

    style A fill:#f9f
    style P fill:#9f9

Step-by-Step Process:

  1. Codec Selection: During HCM creation, the codec type is determined from config (AUTO_DETECT, HTTP1, HTTP2, HTTP3). AUTO_DETECT reads the initial bytes and ALPN to select. The codec is created in source/common/http/conn_manager_impl.cc via createCodec().

  2. Stream Creation: When the codec parses request headers, it calls newStream() on the HCM, which creates an ActiveStream. The ActiveStream is the central object for a single request lifecycle—it holds references to the filter chain, route, request/response headers, and watermark state.

  3. Filter Chain Execution (Decode Path): ActiveStream::decodeHeaders() iterates through HTTP filters in order (configured in http_filters field). Each filter receives headers, data, and trailers callbacks. Filters can:

    • Continue: Pass to the next filter.
    • StopIteration: Pause (e.g., waiting for external auth). Call continueDecoding() to resume.
    • StopAllIterationAndBuffer: Buffer all data until resumed.
    • Directly send a local reply (e.g., 403 from auth filter) via sendLocalReply().
  4. Route Resolution: Typically happens in the router filter or earlier (some filters access the route for config). Route tables are loaded from RDS or inline config. Route matching checks domains, paths, headers, and query parameters against RouteEntry objects in source/common/router/config_impl.cc.

  5. Upstream Dispatch: The Router filter (terminal filter) in source/common/router/router.cc selects the upstream cluster, picks a host via load balancer, acquires a connection from the pool, and forwards the request. It handles retries, timeouts, and hedging.

  6. Encode Path: Upstream response flows back through encodeHeaders() / encodeData() / encodeTrailers() in reverse filter order. Filters can modify response headers (e.g., add CORS headers, strip internal headers).

  7. Access Logging: After the response completes (or on stream reset), the HCM invokes all configured access loggers (source/common/http/conn_manager_impl.cc:doDeferredStreamDestroy()). Log formats support command operators (%REQ()%, %RESP()%, %DURATION%, etc.).

  8. Idle/Timeout Management: The HCM tracks idle timeouts (close connection after inactivity), stream timeouts (per-request deadline), and drain timeouts (graceful shutdown). These are managed via libevent timers on the worker’s dispatcher.

Design Patterns & Trade-offs:

  • Per-stream filter instances: Each stream gets its own filter chain instances, providing isolation but costing allocations. Mitigated by arena/pool allocators for common filter types.
  • Codec abstraction: A single ServerConnection interface hides HTTP/1.1 vs HTTP/2 vs HTTP/3 differences. Trade-off: some protocol-specific behaviors leak through (e.g., HTTP/2 flow control, HTTP/1.1 connection-level vs stream-level).
  • Watermark-based backpressure: High watermark on downstream buffers triggers StopIteration upstream, preventing memory blowup on slow clients. Complex but necessary for production stability.
  • Route config caching: Route tables from RDS are shared (read-only) across all streams via shared_ptr. Updates are atomic (swap pointer via TLS).

Key Code Paths

Core HCM Implementation

HCM Extension Filter Factory

HTTP Codecs

Filter Chain Management

Route Configuration

Configuration

The HCM is configured via the envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager protobuf:

FieldTypeDefaultEffect
codec_typeenumAUTO_DETECTHTTP protocol: AUTO_DETECT, HTTP1, HTTP2, HTTP3
stat_prefixstringrequiredPrefix for HCM stats (http.<prefix>.downstream_cx_*)
route_configRouteConfiguration-Inline route table (mutually exclusive with rds)
rdsRds-RDS config source for dynamic routes
http_filtersrepeated HttpFilterrequiredOrdered filter chain, must end with envoy.filters.http.router
server_namestring”envoy”Server header value
stream_idle_timeoutDuration5mPer-stream idle timeout (0 to disable)
request_timeoutDuration0 (disabled)Total request timeout (headers + body)
drain_timeoutDuration5sTime to wait for active streams during drain
access_logrepeated AccessLog-Access log sinks (file, gRPC, etc.)
use_remote_addressboolfalseTrust XFF or use direct downstream IP
tracingTracing-Distributed tracing config (Zipkin, Jaeger, OpenTelemetry)
common_http_protocol_optionsHttpProtocolOptions-Idle/max connection timeouts
http2_protocol_optionsHttp2ProtocolOptions-HTTP/2 specific: max concurrent streams, initial window size

See api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto for the full protobuf definition.

Extension Points

  1. Custom HTTP Filters:

    • Implement Http::StreamDecoderFilter and/or Http::StreamEncoderFilter interfaces.
    • Create a NamedHttpFilterConfigFactory that produces filter instances from protobuf config.
    • Register with REGISTER_FACTORY(MyFilterFactory).
    • Add to http_filters list in HCM config.
    • Example: See source/extensions/filters/http/rbac/ for a complete filter implementation.
  2. Custom Access Loggers:

    • Implement AccessLog::Instance interface.
    • Register factory via REGISTER_FACTORY.
    • Add to HCM access_log config.
    • Built-in: file, gRPC, stderr, OpenTelemetry.
  3. Custom Route Matching:

    • Implement Router::RouteSpecificFilterConfig for per-route filter overrides.
    • Custom matchers via InputMatcher interface for header/query matching extensions.
  4. Wasm Filters:

  5. Custom Codecs:

    • Implement Http::ServerConnection / Http::ClientConnection interfaces.
    • Register codec factory. Used for dubbo, thrift, and other protocols wrapped as HTTP.

To develop: Use bazel test //test/extensions/filters/network/http_connection_manager/... for HCM-specific tests. The IntegrationTest fixture in test/integration/ provides end-to-end testing with real listeners.