Commit 03c6723
net.http: add synchronous HTTP/2 client connection (H2Conn) (#27361)
* net.http: add synchronous HTTP/2 client connection (H2Conn)
Build on the ALPN (#27343), HPACK (#27353), and frame-codec (#27356) PRs to add
a minimal, synchronous, single-stream HTTP/2 client. Additive only: new files in
the http module, no change to existing code paths. Nothing wires it into
http.fetch yet (that ALPN shim is a follow-up), so there is no user-visible
behaviour change.
- H2Transport interface — the byte transport the connection runs over. Its
read/write signatures match net.ssl.SSLConn, so an ALPN-negotiated `h2` TLS
socket satisfies it directly; tests use an in-memory mock, so the connection
is exercised without a socket.
- Connection preface + SETTINGS handshake (sent lazily on the first request).
- H2Conn.do(req): HPACK-encodes the request headers, sends HEADERS (plus DATA
for a body, chunked to the peer's max frame size and bounded by the
connection flow-control window), then reads frames until the stream closes.
- Inline servicing of connection-level frames: SETTINGS (apply + ACK), PING
(echo ACK), WINDOW_UPDATE (grow the send window), GOAWAY (fail). Receive-side
flow control is replenished with a WINDOW_UPDATE per DATA frame.
- CONTINUATION reassembly for response header blocks; RST_STREAM on the request
stream is surfaced as an error.
Hermetic tests over the mock transport cover: a basic GET, a multi-DATA
response, a POST with a body, GOAWAY, RST_STREAM, CONTINUATION-split response
headers, and PING ACK. Passes under -W -cstrict -cc clang; the full
vlib/net/http suite is green.
Not included here, by design (follow-ups): stream multiplexing with a
background reader thread, connection pooling, wiring into http.fetch via ALPN,
and the server side.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* net.http: HTTP/2 client header splitting and per-stream flow control
Address two send-path correctness gaps in H2Conn:
- Split request header blocks larger than the peer's SETTINGS_MAX_FRAME_SIZE
into a HEADERS frame followed by CONTINUATION frames (RFC 7540 Section 4.3),
via send_header_block. Previously a large header set (e.g. big Cookie or
Authorization) was sent as one oversized HEADERS frame that a compliant peer
would reject.
- Track the per-stream send window in addition to the connection window
(RFC 7540 Section 6.9). DATA is now bounded by min(connection, stream)
window, stream-level WINDOW_UPDATE credits the active stream, and a change to
SETTINGS_INITIAL_WINDOW_SIZE retroactively adjusts the stream window by the
delta (Section 6.9.2). Previously only the connection window was tracked, so
a peer lowering the initial window or granting stream-level updates could be
overrun or could stall the client.
Adds tests for a request whose header block spans HEADERS + CONTINUATION, and
for a body larger than the initial window that resumes after the peer grows
both windows (no DATA frame exceeding the max frame size).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Richard Wheeler <quaesitor.scientiam@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>1 parent e78b731 commit 03c6723
2 files changed
Lines changed: 812 additions & 0 deletions
0 commit comments