feat(core): add HTTP/2 cleartext proxy support

This commit is contained in:
Zakaria El Orche
2026-08-13 20:00:59 +00:00
parent 5755ef77fe
commit 3c1eb0d0df
27 changed files with 1593 additions and 109 deletions
+42
View File
@@ -0,0 +1,42 @@
# HTTP/2 cleartext and proxying
TLS HTTP/2 and cleartext HTTP/2 have independent rollout controls:
- `http2Enabled` advertises `h2` through TLS ALPN.
- `http2CleartextEnabled` accepts the HTTP/2 prior-knowledge preface on plaintext listeners.
Both default to `false`. Cleartext support follows RFC 9113 prior knowledge. The obsolete
HTTP/1.1 `Upgrade: h2c` transition is intentionally unsupported.
## Upstream client
`Http2Client` is a synchronous, pooled client for reverse-proxy handlers. It supports TLS ALPN and
h2c prior knowledge, request and response bodies, flow control, response status, trailers,
SETTINGS, PING, GOAWAY and RST_STREAM. Connections are pooled by origin and reused across
sequential exchanges. A connection serializes its exchanges deliberately; this keeps ownership
and HPACK state explicit and bounded while virtual threads allow independent origins to progress.
It is not intended to replace a general-purpose HTTP client.
`HttpProxy.toHttp2(origin, client)` adapts Flash's shared `Request` and `Response` models to that
client. It preserves the incoming raw path and query, body, end-to-end fields and trailers.
## Header conversion
`HopByHopHeaders` is the single policy used at connection boundaries. It removes fields named by
`Connection`, the standard hop-by-hop set, HTTP/2-forbidden fields and pseudo-fields. `TE` is
forwarded only as `trailers` when the target is HTTP/2. Tests execute the same policy for all four
HTTP/1.1 and HTTP/2 source/target combinations.
## Authority and 421
On TLS HTTP/2 connections, Flash checks `:authority` against the selected certificate's DNS/IP
subject alternative names. An authority outside that served set receives `421 Misdirected
Request`, allowing a coalescing client to retry on a different connection. Exact names and
single-label wildcards are supported; h2c has no certificate identity and is unaffected.
## Trailer guarantee
The proxy copies request trailers only after the incoming body reaches EOF and emits upstream
trailers as a trailing HEADERS block. Response trailers follow the reverse path and remain
trailers on both HTTP/2 and HTTP/1.1 chunked downstream connections. The live relay tests cover
both downstream protocols.
+27 -7
View File
@@ -982,23 +982,22 @@ window and pool byte capacity together; never raise credit independently of boun
---
## DEC-29 — Keep HTTP/2 opt-in through the cleartext rollout boundary
## DEC-29 — Keep TLS HTTP/2 opt-in until the compliance gate
**Context.** Trailers and push streaming make the protocol feature-complete for ordinary and gRPC-
shaped traffic, but the dedicated rate-based and composite abuse controls are deliberately owned
by the following security phase.
**Decision.** Keep `FlashConfiguration.http2Enabled` defaulting to `false`. Applications can
enable the complete path explicitly. The Phase 13 hostile-peer suite is now green, but the same
flag currently also admits cleartext prior-knowledge traffic; Phase 14 owns splitting that into a
separate `http2CleartextEnabled` opt-in before the general protocol default can change safely.
**Decision.** Keep `FlashConfiguration.http2Enabled` defaulting to `false`. Phase 14 separates
cleartext behind its own `http2CleartextEnabled` opt-in, also defaulting to `false`. Passing the
hostile-peer gate removes the security blocker, but changing the TLS default remains deferred
until the complete external conformance gate is green.
**Consequence.** Existing deployments do not silently expose a newly completed protocol before its
adversarial gate. This is rollout sequencing, not an architectural separation: both protocols use
the same public request/response, header, trailer and streaming APIs.
**Revisit when.** At Phase 14 closure, after TLS HTTP/2 and cleartext h2c have independent rollout
controls.
**Revisit when.** At Phase 16 closure, after the external compliance matrix is green.
---
@@ -1022,3 +1021,24 @@ thread. A fixed control-intent pool and one-in-flight intent per live stream bou
aggregate default; tune the threshold from evidence without splitting the defence by frame type.
---
## DEC-31 — Keep the upstream HTTP/2 client proxy-oriented and single-owner
**Context.** A general-purpose HTTP client would introduce a second large public API, redirect,
cookie, authentication and retry policy, while the immediate requirement is a reliable Flash
reverse-proxy hop with trailers.
**Decision.** Pool one reusable connection per origin and serialize exchanges on that connection.
Reuse the core frame reader/writer and HPACK codec, but keep response assembly and ownership inside
the client connection. Expose `HttpProxy.toHttp2` as the protocol-neutral adapter and one shared
`HopByHopHeaders` policy for every conversion direction.
**Consequence.** HPACK and socket state have one clear owner, upstream connections are reused, and
trailer semantics cannot diverge by downstream protocol. Concurrent calls to one origin queue
behind its active exchange rather than pretending this minimal client is a fully multiplexed
general-purpose stack.
**Revisit when.** Proxy production traces show per-origin serialization is a bottleneck; add a
bounded pool or client-side multiplexing without changing the proxy-facing API.
---
+3 -3
View File
@@ -75,7 +75,7 @@ Status values: `not started` / `in progress` / `blocked` / `done`.
| 11 — DATA, flow control, bodies | done | `feature/core/http2` | Two-level receive/send flow control, consumption-driven WINDOW_UPDATE hysteresis, bounded/coalescing DATA pool, inline and blocking streaming request bodies through the existing `RequestBody`, resumable fixed/known/unknown response streams, content-length and empty-DATA validation. Real TLS HTTP/2 transfer: 100 MiB upload + 100 MiB download verified byte-for-byte. h2spec combined sections 5, 6.1, 6.9 and 8: 50 passed, 1 tool-skipped, 0 failed. JMH: inline materialization exactly one 1,040-byte array; request streaming 0.001 B/op; response streaming 0.002 B/op; full pooled lifecycle 0.003 B/op. 633/633 tests green from a clean `-Pjmh` build. |
| 12 — Trailers, half-close, gRPC | done | `feature/core/http2` | Protocol-neutral request/response trailers, bounded push streaming, four half-close orderings and authority-form CONNECT tunnels complete. Real grpcurl 1.9.3 unary/server-streaming/error interop passes. EX-48/49 fixed. HTTP/2 remains opt-in until the Phase 13 hostile-peer gate (DEC-29). 649/649 tests green from a clean `-Pjmh` build. |
| 13 — Security hardening & abuse resistance | done | `feature/core/http2` | Two-bucket Rapid Reset/stream/settings/ping/aggregate counters, control/write queue bounds, optional stream/byte/lifetime budgets, absolute header and idle-stream deadlines, and hostile-peer suite complete. Security review found+fixed EX-50/51. JMH counter: 38.083 ns/op, ~10^-4 B/op, no GC. 100k-CONTINUATION attack terminates in under 2 s with bounded retained heap. 663/663 tests green from a clean `-Pjmh` build. |
| 14 — h2c prior knowledge + proxy support | not started | — | — |
| 14 — h2c prior knowledge + proxy support | done | `feature/core/http2` | Independent TLS/h2c gates, pooled proxy-oriented h2 client with TLS ALPN and h2c, bidirectional h1/h2 trailer relay, shared four-direction hop-by-hop policy and certificate-backed 421 handling complete. Real grpcurl h2c interop passes. 670/670 tests green from a clean `-Pjmh` build. |
| 15 — RFC 8441 extended CONNECT (WS over h2) | not started | — | — |
| 16 — Compliance test suite | not started | — | — |
| 17 — Benchmarks, allocation gates, tuning | not started | — | — |
@@ -2906,8 +2906,8 @@ speak h2 as a **client** so Pathway can proxy.
`flash/docs/http2/CLEARTEXT-AND-PROXY.md`.
### DoD
- [ ] gRPC over h2c works end to end.
- [ ] Trailers survive a Flash→Flash proxy hop in both directions.
- [x] gRPC over h2c works end to end.
- [x] Trailers survive a Flash→Flash proxy hop in both directions.
---