envoyproxy/envoy
Router
The router is the terminal HTTP filter — the one that turns a routed request into an upstream request. It lives in source/common/router/ (the implementation) and is wired in as a filter via source/extensions/filters/http/router/ (the factory).
Purpose
Given a request that has made it through every other HTTP filter, the router:
- Looks up the matching
Routein the configuredRouteConfiguration(or scoped/RDS-supplied one). - Applies host rewrites, header mutations, and request-level features (timeouts, retries, hedging, mirrors).
- Picks an upstream
HostDescriptionvia the cluster manager's load balancer. - Acquires an upstream connection from the appropriate connection pool.
- Forwards the request and streams the response back through the encoder filter chain.
Layout
| File | Role |
|---|---|
router.cc (~2,600 lines) |
The Router::Filter HTTP filter — the per-request engine. |
router.h |
Filter declaration plus FilterUtility helpers. |
config_impl.h and config_impl.cc (~100k lines) |
The RouteConfiguration parser and matcher tree (virtual hosts → routes → clusters). |
upstream_request.h and .cc |
The UpstreamRequest object representing a single attempt against an upstream host. |
upstream_codec_filter.cc |
The terminal filter on the upstream filter chain. |
retry_state_impl.cc |
Retry decisions (status codes, retry-on, retry budget). |
shadow_writer_impl.cc |
Request mirroring. |
rds_impl.cc, scoped_rds.cc, vhds.cc |
RDS, Scoped-RDS, and VHDS subscription glue. |
router_ratelimit.cc |
Builds rate-limit descriptors from route metadata. |
Key abstractions
| Type | Role |
|---|---|
Router::Filter (router.h) |
The HTTP filter implementation; one per stream. |
Router::ConfigImpl (config_impl.h) |
Parsed RouteConfiguration — vhosts, routes, retry policies. |
Router::RouteEntryImplBase (config_impl.h) |
A single route entry: match, action, header mutations, retry policy, timeouts. |
Router::UpstreamRequest (upstream_request.h) |
One in-flight attempt against an upstream — knows the connection pool, encoder, retry attempt index. |
Router::RetryState (retry_state_impl.h) |
Per-stream retry decisions. |
Router::ShadowWriter (shadow_writer_impl.h) |
Async fire-and-forget mirroring. |
Path through Router::Filter::decodeHeaders
flowchart TD
Start(decodeHeaders) --> Match[match route<br/>RouteConfiguration]
Match -->|no match| LocalReply404[encodeHeaders 404]
Match --> ClusterLookup[cluster_manager_.getThreadLocalCluster]
ClusterLookup -->|no cluster| LocalReply503[encodeHeaders 503]
ClusterLookup --> RewriteHost[host rewrite, header mutations]
RewriteHost --> LB[cluster.loadBalancer().chooseHost]
LB -->|no host| LocalReplyNoHealthy[encodeHeaders 503]
LB --> CP[choose conn pool by protocol/transport]
CP --> Send[UpstreamRequest::startUpstreamRequest]
Send --> Codec[upstream codec encodes]The same code path handles HTTP/1, HTTP/2, and HTTP/3 upstreams; the protocol comes from the cluster's ClusterInfo and dictates which connection pool family is used.
Retries
RetryStateImpl (retry_state_impl.cc) decides whether to retry, based on:
- The route's
retry_policy(e.g.5xx,gateway-error,reset,retriable-headers,retriable-status-codes). - The
x-envoy-retry-on,x-envoy-max-retriesrequest headers. - A retry budget on the cluster.
- A pluggable retry priority and host predicate (see
source/extensions/retry/).
Each retry creates a fresh UpstreamRequest. Hedged requests run two UpstreamRequests in parallel, returning the faster.
Mirroring
When a route specifies request_mirror_policies, the router asks ShadowWriter to fire a copy of the request at the mirror cluster asynchronously. The mirror's response is discarded; only the primary affects the client. The mirror cluster runs through the full filter chain on the upstream side.
Internal redirects
If the upstream returns a 3xx and the route allows it, Router::Filter::handleInternalRedirect rewrites the request and re-enters the chain via decoder_callbacks_->recreateStream. The decision logic is pluggable via source/extensions/internal_redirect/.
Upstream filter chain
After upstream codec selection, a small upstream-side filter chain runs on the upstream Http::ConnectionPool::Instance. The terminal filter is UpstreamCodecFilter (upstream_codec_filter.cc), which writes the request onto the chosen codec. Custom upstream filters live in source/extensions/filters/http/upstream_codec/... style directories and are configured per-cluster.
Stream info enrichment
The router populates several fields on StreamInfo:
upstream_host_upstream_local_address_upstream_cluster_info_route_name_,virtual_cluster_name_attempt_count_for retries
These are consumed by access loggers and stat sinks downstream.
Stats
The router emits per-cluster stats (counters for upstream_rq_2xx, upstream_rq_retry, upstream_rq_per_try_timeout, etc.) via a StatNames struct (router.h). Per-route stats (virtual_clusters, route_specific) require explicit configuration.
Integration points
- HTTP connection manager. The router is one of the HTTP filters; without an HCM there is no router.
- Cluster manager (cluster manager). The router calls
getThreadLocalClusterper request. - Connection pools (connection pools). The router asks for a pool, then calls
newStream. - xDS / RDS / VHDS / Scoped-RDS. Route configurations can be statically defined, RDS-pushed, or scoped (a key from the request selects which RouteConfig).
- Tracing (tracing). The router sets the upstream span attributes.
- Access logs. Final
StreamInfois emitted by the HCM after the router completes.
Entry points for modification
- Adding retry semantics: read
RetryStateImpland theretryextensions. - Adding routing primitives (e.g. a new path matcher): the proto lives in
api/envoy/config/route/v3/; the parser is inconfig_impl.cc. - Adding a request-level feature flag: usually a runtime guard in
router.ccplus a newRetryPolicy/RouteActionfield. - Replacing the upstream codec: implement a custom
Upstream::UpstreamCodecFactoryor wire in viaUpstreamHttpFilterFactory.
See also
- HTTP connection manager — the filter chain the router runs in.
- Cluster manager — host selection.
- Connection pools — upstream connection lifecycle.
- HTTP filters — the broader L7 filter family.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.