Expand description
HTTP/3 (QUIC) upstream transport (DW-108).
The mirror of the DW-088 H3 ingress listener: an H3 egress
connector that dials upstream endpoints over QUIC and speaks
HTTP/3 on bidirectional QUIC streams. A route whose upstream is
configured protocol: h3 dispatches through here instead of the
TCP/TLS pooled client in super::upstream.
§Transport model
QUIC multiplexes many streams over one connection, so the pool
shape is inverted relative to HTTP/1.1: a QUIC connection is the
pooled resource, and each request opens a fresh bidirectional stream
within it. QuicStreamPool keeps a bounded set of QUIC
connections per endpoint address, hands out a cheaply cloneable
[h3::client::SendRequest] handle per request (one stream per
send_request call), and reaps connections idle past
QuicStreamPool::idle_timeout.
§TLS
QUIC mandates TLS 1.3, so every H3 upstream negotiates TLS with
ALPN h3. The trust roots are the SAME ones the pooled https
connector uses (#121): the Mozilla webpki public set by default, or
the upstream’s trusted_ca_file bundle when configured. The shared
rustls client-config shape lives in crate::security::tls
(https_h3_client_config) so the connector and the QUIC active
health probe can never disagree about trust.
§0-RTT
Deliberately NOT used for upstream dialing: 0-RTT early data is
replayable, and a replayed non-idempotent upstream request is a
footgun the gateway must not expose by default. The rustls client
config disables early data (https_h3_client_config).
§Response streaming (PERF-10, #243)
The H3 transport supports two response modes:
h3_request: buffers the full response body (the original v1 behavior; kept for compatibility and simple use cases).h3_request_streaming: streams the response body through a tokio channel as h3recv_datachunks arrive, matching the h1/h2 zero-buffer guarantee. The driver task readsrecv_dataand sends each chunk through a bounded channel (capacity 1) so backpressure flows from the consumer to the upstream. The caller wraps the receiver inUpstreamBody::from_h3_streamingto get ahyper::Body-compatible streaming body with the idle/deadline/health knobs.
The request body is still sent as one DATA frame (the proxy
already buffers request bodies for retries); streaming request
bodies are a separate enhancement.
Everything in this module is compiled into the OSS build; H3 upstreams are always available.
Structs§
- H3Upstream
Handle - Per-upstream H3 transport handle: a
QuicStreamPoolplus the per-upstream timeouts and shared stats. Stored onsuper::upstream::UpstreamHandlefor the H3 transport; the LB, breaker, retry, and health layers are shared with the TCP/TLS path (they operate on endpoint addresses, not the transport). - Quic
Stream Pool - QUIC stream-aware connection pool: a bounded set of QUIC connections
per endpoint address, each carrying many H3 streams. One
QuicStreamPoolserves one upstream (the per-upstream connection cap and trust roots are fixed at build time); endpoint addresses are the inner key so a multi-endpoint upstream shares one pool.
Enums§
- H3Error
- Errors specific to the H3/QUIC upstream transport. Mapped onto the
shared
UpstreamErrorbyH3UpstreamHandle::sendso the proxy, breaker, and health layers stay transport-agnostic.
Constants§
- DEFAULT_
H3_ CONNECTION_ CAP - Default maximum QUIC connections per endpoint address when the
upstream’s
connection_capis absent. Lower than the TCP/TLS default (64): one QUIC connection carries many streams, so a handful of connections saturates concurrency without the per-stream head-of-line blocking that makes TCP pools need many connections. - DEFAULT_
H3_ IDLE_ TIMEOUT_ MS - Default idle timeout for a pooled QUIC connection (no streams opened through it for this long => close and reap). QUIC’s own keep-alive is not configured here; the sweep is the reaper.
Functions§
- h3_
request - Send an HTTP/3 request over a QUIC stream (one
send_requestcall = one bidirectional stream) and read the full response. The request body is sent as a singleDATAframe (the H3 path buffers the request body; see the module docs); the response body is collected into one [Bytes] (streaming H3 response bodies are a follow-up). - h3_
request_ streaming - Send an HTTP/3 request over a QUIC stream and return a STREAMING
response body (PERF-10, #243). The response headers are returned
immediately; the body is forwarded through a tokio channel as h3
recv_datachunks arrive, matching the h1/h2 zero-buffer guarantee.