158 lines
9.5 KiB
Markdown
158 lines
9.5 KiB
Markdown
# HTTP/3 transport (0.22.3)
|
|
|
|
**Uncompiled development source in this environment.** This release adds an actual
|
|
QUIC/HTTP/3 adapter, not only an Alt-Svc header. It does not claim independent full-RFC
|
|
conformance, interoperability or production performance until the acceptance tests run.
|
|
|
|
## Stack and configuration
|
|
|
|
The adapter delegates QUIC transport/TLS to Quinn 0.11.12 and HTTP/3/QPACK plus the
|
|
Quinn adapter to `hpx-h3 2.5.19` with its `quinn` feature. The crate is imported as `h3`
|
|
in source. These are Cargo dependencies, not bundled binaries.
|
|
Rustls provides TLS 1.3 for QUIC; SNI certificates come from the existing inventory.
|
|
HTTP/1.1 and optional HTTP/2 remain on TCP at the same port. HTTP/3 is on UDP.
|
|
There is no HTTP/3 upstream client in this revision: origins still use HTTP/1.1 or HTTP/2.
|
|
|
|
Each vhost has `http3_enabled` (default true). When false, RustProxy removes
|
|
`Alt-Svc` from responses for that vhost and rejects HTTP/3 requests for it with 421,
|
|
while HTTP/1.1 and any permitted HTTP/2 traffic on the selected TLS listener keep
|
|
working. The UDP listener is still a listener-level resource; the vhost switch narrows
|
|
use of that shared capability rather than hot-unbinding the UDP socket.
|
|
|
|
HTTP/2 follows the same UI model through `http2_enabled` (default true). A vhost may
|
|
only opt into H2 when one of its selected named listeners enables H2. For TLS, RustProxy
|
|
reads ClientHello/SNI before finishing the handshake and selects H2+HTTP/1.1 or
|
|
HTTP/1.1-only ALPN for that vhost. The listener remains the capability ceiling.
|
|
|
|
|
|
Since 0.5.0, an omitted `http3` enables QUIC with defaults on TLS bindings.
|
|
Explicit `http3: null` disables it and is preserved when serialized. An object
|
|
enables it with chosen limits. Plain HTTP defaults to no QUIC. In 0.24.3 the
|
|
**Enable HTTP/3 over QUIC (UDP)** switch is edited with the TLS endpoint under
|
|
**Settings -> Listeners**. The listener row links to **Settings -> HTTP connections
|
|
-> HTTP/3**, which contains only advertisement, connection, stream and idle-timeout
|
|
tuning for listeners where H3 is enabled. Both enablement and tuning remain
|
|
restart-required. Configure this only on named `listeners.endpoints[].binding`:
|
|
|
|
```json
|
|
{
|
|
"address": "127.0.0.1:8443",
|
|
"tls": true,
|
|
"http2": true,
|
|
"http3": {
|
|
"alt_svc_max_age": 3600,
|
|
"max_concurrent_connections": 512,
|
|
"max_concurrent_bidistream": 100,
|
|
"max_concurrent_unistream": 100,
|
|
"max_idle_timeout": 10
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Meaning and accepted limits |
|
|
|---|---|
|
|
| alt_svc_max_age | Advertisement lifetime, seconds, 0..604800 |
|
|
| max_concurrent_connections | Established/pending accepted connection slots per endpoint, 1..4096 |
|
|
| max_concurrent_bidistream | Peer bidirectional streams per connection, 1..1024 |
|
|
| max_concurrent_unistream | Peer unidirectional streams per connection, 3..1024 |
|
|
| max_idle_timeout | QUIC idle timeout, seconds, 0..86400; zero means no local QUIC idle timeout |
|
|
|
|
Three unidirectional streams are required for the peer control and QPACK streams.
|
|
These stream limits are NOT global to all listeners. The existing global in-flight
|
|
request and application body/header deadlines still apply. Setting QUIC idle to zero
|
|
does not disable application deadlines, and the peer can negotiate its own idle timeout.
|
|
All changes to socket/ALPN/QUIC transport parameters require restart.
|
|
|
|
## Transport behavior and safety
|
|
|
|
- Bind UDP before announcing readiness; failure to bind is a startup failure.
|
|
- Advertise `Alt-Svc: h3=":port"; ma=N` only on an ACTUAL active TLS+H3 endpoint.
|
|
Origin Alt-Svc is stripped so it cannot advertise the origin or a disabled service.
|
|
- UDP address validation/Retry, bounded pending handshakes, a 10-second handshake
|
|
deadline, per-endpoint permits, stream flow control and bounded application concurrency.
|
|
- 32 KiB decoded HTTP field section limit; request content-length checks and rejection
|
|
of forbidden connection/framing headers; streamed bodies and trailers.
|
|
- Shared routing pipeline: real local socket -> validated authority -> trusted client
|
|
address -> ACL -> Tinyauth -> cache -> origin -> response/security/Server policies.
|
|
- 0-RTT is disabled to avoid replaying writes; no retry to another origin or transport.
|
|
- Endpoint active migration is disabled. Missing real local destination data on a
|
|
wildcard QUIC connection fails closed rather than substituting a forwarded IP.
|
|
- Configuration reload changes SNI certificates for new QUIC handshakes without
|
|
changing active socket limits. Graceful shutdown requests GOAWAY then bounded drain.
|
|
- Counters: http3_requests, http3_connections, http3_active_connections and
|
|
http3_rejected_connections in status/Prometheus; H3 request count also in dashboard.
|
|
|
|
A connection receives a maximum aggregate 8 MiB QUIC window and 256 KiB per-stream
|
|
window; these limits are not process memory guarantees. Many simultaneous connections
|
|
can use substantial memory. Size connection/stream limits to the machine and measure.
|
|
No active path migration, 0-RTT, server push, WebTransport or HTTP datagrams are enabled.
|
|
RFC 9220 WebSocket Extended CONNECT is experimental and disabled by default per vhost.
|
|
RustProxy advertises SETTINGS_ENABLE_CONNECT_PROTOCOL on a QUIC listener only when at least
|
|
one vhost bound to that listener explicitly enables `websocket_rfc9220`; request routing
|
|
still rejects RFC 9220 for vhosts that did not opt in. Generic CONNECT and other Extended
|
|
CONNECT protocols remain unsupported and are answered with 501. The downstream H3 request must
|
|
not carry HTTP/1.1-only `Connection`, `Upgrade`, `Sec-WebSocket-Key` or
|
|
`Sec-WebSocket-Accept` fields. RustProxy creates a private RFC 6455 key for the HTTP/1.1
|
|
backend handshake; a valid backend `101` becomes downstream `200`, after which H3 DATA
|
|
bytes are the WebSocket byte stream. Client FIN half-closes the backend write side;
|
|
backend EOF finishes the H3 send side; abnormal/forced termination uses
|
|
`H3_REQUEST_CANCELLED`. No side TCP listener or protocol bypass is used.
|
|
|
|
### WebSocket bootstrap ordering and diagnostics in 0.16.0
|
|
|
|
For RFC 9220, a validated backend `101` is no longer enough to send the client-facing H3 success immediately. RustProxy first awaits Hyper's backend `OnUpgrade` and obtains the actual upgraded stream. Only then is downstream `200` returned and the H3 DATA bridge started. If backend takeover is cancelled or fails, the client receives a normal 503/502 response instead of `200` followed by an immediate `H3_REQUEST_CANCELLED` reset.
|
|
|
|
Access logging can now distinguish this path with `http_version`, `transport`, `websocket_bootstrap`, `websocket_phase`, `websocket_error`, `h3_reset_code` and `upstream_status`. This makes Safari/iOS interoperability failures distinguishable from backend Socket.IO responses and from H3 tunnel resets. Query-string logging remains subject to the normal privacy policy; do not use access logging to capture session secrets.
|
|
|
|
The advertised port is the real listener port. Behind port-rewriting NAT, use a
|
|
matching externally reachable UDP/TCP port or do not enable this advertisement; there
|
|
is no separate external-port override. Open UDP as well as TCP in your firewall/load
|
|
balancer. Scope labels do not perform those operations. Clients lacking QUIC or blocked
|
|
UDP can still connect using TCP; no guarantee is made about browser protocol preference.
|
|
|
|
## Verification gate
|
|
|
|
```bash
|
|
bash dev.sh check
|
|
cargo test --locked --test http3 -- --nocapture
|
|
cargo test --locked --test integrations --test listeners
|
|
bash dev.sh test
|
|
```
|
|
|
|
`tests/http3.rs` creates a real loopback UDP endpoint, a trusted generated test
|
|
certificate, a real origin and a Quinn+h3 client. It checks MISS/HIT, body preservation,
|
|
Server/diagnostic policy, connection capacity and ALPN HTTP/2/HTTP/1.1 compatibility.
|
|
The same integration test explicitly enables `websocket_rfc9220`, then opens an RFC 9220 Extended CONNECT stream and translates it
|
|
to a real HTTP/1.1 backend Upgrade, sends a masked WebSocket frame as H3 DATA, half-closes
|
|
the client send side and verifies byte-transparent DATA return plus tunnel metrics. Unit
|
|
regressions separately reject HTTP/1.1-only proof/framing headers on the H3 side.
|
|
It is provided but was NOT run in the packaging environment. The same-stack client
|
|
is a regression test, not independent interoperability evidence.
|
|
|
|
After applying examples/http3-vhost.json on a disposable test instance and starting
|
|
`bash dev.sh mock --port 9001`, use an independently built curl with HTTP3 support:
|
|
|
|
```bash
|
|
curl --version
|
|
curl --http3-only --cacert data/certs/default.pem -D - https://localhost:8443/cache
|
|
curl --http3-only --cacert data/certs/default.pem -D - https://localhost:8443/cache
|
|
curl --http2 --cacert data/certs/default.pem -D - https://localhost:8443/cache
|
|
curl --http1.1 --cacert data/certs/default.pem -D - https://localhost:8443/cache
|
|
```
|
|
|
|
Do not substitute `--http3` fallback or `-k` for strict protocol/certificate validation.
|
|
Also test independent clients, malformed-frame handling, stream exhaustion, slow
|
|
uploads/downloads, IPv6 wildcard destination metadata, cancellation, graceful drain,
|
|
certificate rotation, and memory/CPU at configured maxima before exposure.
|
|
No full RFC conformance or load-test result is asserted by this source package.
|
|
|
|
## Primary references
|
|
|
|
- HTTP/3 RFC 9114: https://www.rfc-editor.org/rfc/rfc9114.html
|
|
- QUIC RFC 9000: https://www.rfc-editor.org/rfc/rfc9000.html
|
|
- QPACK RFC 9204: https://www.rfc-editor.org/rfc/rfc9204.html
|
|
- Quinn: https://docs.rs/quinn/latest/quinn/
|
|
- RFC 8441 Extended CONNECT: https://www.rfc-editor.org/rfc/rfc8441.html
|
|
- RFC 9220 WebSocket over HTTP/3: https://www.rfc-editor.org/rfc/rfc9220.html
|
|
- hpx-h3 2.5.19: https://docs.rs/hpx-h3/2.5.19/h3/
|