net.http: add HTTP/2 frame codec (RFC 7540)#27356
Merged
Merged
Conversation
Add the HTTP/2 binary framing layer: encoders and decoders for all ten frame types plus a fallthrough for unknown types. Like the HPACK PR, this is purely additive (new files in the http module) and does not touch any existing net.http code path; nothing calls it yet. Included: - H2FrameHeader parsing of the 9-byte header, ignoring the reserved bit. - A H2Frame sum type with DATA, HEADERS, PRIORITY, RST_STREAM, SETTINGS, PUSH_PROMISE, PING, GOAWAY, WINDOW_UPDATE, CONTINUATION, and an UnknownFrame variant. Unknown frame types are preserved rather than rejected, as required by RFC 7540 Section 4.1. - h2_read_frame / h2_parse_frame decoders and an .encode() method, with PADDED and PRIORITY handling for HEADERS/DATA/PUSH_PROMISE. - Structural validation that maps to FRAME_SIZE_ERROR / PROTOCOL_ERROR at the connection layer: fixed-size frames (PRIORITY, RST_STREAM, PING, WINDOW_UPDATE), SETTINGS payload as a multiple of 6 with empty ACK, and the stream-id rules (DATA/HEADERS/etc. non-zero; SETTINGS/PING/GOAWAY zero). - H2ErrorCode enum (Section 7) and the SETTINGS identifier and frame type/flag constants. Tests cover an encode/decode round-trip for every frame type, the on-wire header layout, reserved-bit masking, padding decode (including pad length exceeding the frame), the priority section on HEADERS, unknown-frame preservation and re-encoding, reading consecutive frames from one buffer, and the structural validation errors above. Passes under -W -cstrict -cc clang. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e79358ae89
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Add comments noting that PRIORITY self-dependency (RFC 7540 Section 5.3.1) and zero WINDOW_UPDATE increments (Section 6.9) are intentionally not rejected by the frame codec. Both are stream errors whose correct handling is RST_STREAM on the affected stream (and, for a zero increment on stream 0, a connection error). That stream-vs-connection distinction belongs to the connection layer, which needs the decoded frame to respond; rejecting in the codec would turn a recoverable stream error into a connection-fatal decode error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 6, 2026
JalonSolov
pushed a commit
that referenced
this pull request
Jun 6, 2026
* 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>
dy-tea
pushed a commit
to wenxuanjun/v
that referenced
this pull request
Jun 19, 2026
* net.http: add HTTP/2 frame codec (RFC 7540) for HTTP/2 Add the HTTP/2 binary framing layer: encoders and decoders for all ten frame types plus a fallthrough for unknown types. Like the HPACK PR, this is purely additive (new files in the http module) and does not touch any existing net.http code path; nothing calls it yet. Included: - H2FrameHeader parsing of the 9-byte header, ignoring the reserved bit. - A H2Frame sum type with DATA, HEADERS, PRIORITY, RST_STREAM, SETTINGS, PUSH_PROMISE, PING, GOAWAY, WINDOW_UPDATE, CONTINUATION, and an UnknownFrame variant. Unknown frame types are preserved rather than rejected, as required by RFC 7540 Section 4.1. - h2_read_frame / h2_parse_frame decoders and an .encode() method, with PADDED and PRIORITY handling for HEADERS/DATA/PUSH_PROMISE. - Structural validation that maps to FRAME_SIZE_ERROR / PROTOCOL_ERROR at the connection layer: fixed-size frames (PRIORITY, RST_STREAM, PING, WINDOW_UPDATE), SETTINGS payload as a multiple of 6 with empty ACK, and the stream-id rules (DATA/HEADERS/etc. non-zero; SETTINGS/PING/GOAWAY zero). - H2ErrorCode enum (Section 7) and the SETTINGS identifier and frame type/flag constants. Tests cover an encode/decode round-trip for every frame type, the on-wire header layout, reserved-bit masking, padding decode (including pad length exceeding the frame), the priority section on HEADERS, unknown-frame preservation and re-encoding, reading consecutive frames from one buffer, and the structural validation errors above. Passes under -W -cstrict -cc clang. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * net.http: document deferred HTTP/2 semantic checks in frame codec Add comments noting that PRIORITY self-dependency (RFC 7540 Section 5.3.1) and zero WINDOW_UPDATE increments (Section 6.9) are intentionally not rejected by the frame codec. Both are stream errors whose correct handling is RST_STREAM on the affected stream (and, for a zero increment on stream 0, a connection error). That stream-vs-connection distinction belongs to the connection layer, which needs the decoded frame to respond; rejecting in the codec would turn a recoverable stream error into a connection-fatal decode error. 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>
dy-tea
pushed a commit
to wenxuanjun/v
that referenced
this pull request
Jun 19, 2026
) * net.http: add synchronous HTTP/2 client connection (H2Conn) Build on the ALPN (vlang#27343), HPACK (vlang#27353), and frame-codec (vlang#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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the HTTP/2 binary framing layer (RFC 7540 Sections 4 & 6) to
net.http: encoders and decoders for all ten frame types, plus a fallthroughfor unknown types.
Like the HPACK PR (#27353), this is purely additive — new files in the
httpmodule, no changes to any existingnet.httpcode path. Nothing callsit yet, so there is no user-visible behaviour change. It is independent of both
#27353 (HPACK) and #27343 (ALPN) and can be reviewed in parallel.
Files
h2_frame.vH2FrameHeader, the per-type frame structs, theH2Framesum type, decoders (h2_read_frame/h2_parse_frame) and.encode()h2_error.vH2ErrorCodeenum (RFC 7540 Section 7)h2_frame_test.vDesign notes
PUSH_PROMISE, PING, GOAWAY, WINDOW_UPDATE, CONTINUATION) modelled as a
H2Framesum type, plusH2UnknownFrame.so the connection layer can ignore them while still advancing the stream.
on HEADERS are decoded; the encoder never emits padding.
FRAME_SIZE_ERROR/PROTOCOL_ERROR: fixed-size frames (PRIORITY,RST_STREAM, PING, WINDOW_UPDATE), SETTINGS payload as a multiple of 6 with an
empty ACK, and the stream-id rules (DATA/HEADERS non-zero; SETTINGS/PING/
GOAWAY zero).
input buffer.
Tests
h2_frame_test.v(internalmodule httptest) covers:ACK with a payload, bad WINDOW_UPDATE/PING length, DATA on stream 0, SETTINGS
on a non-zero stream.
Roadmap
This is the third of several small, independent PRs building toward HTTP/2,
alongside #27343 (ALPN in net.ssl) and #27353 (HPACK). With framing and HPACK in
place, the next step is the client connection state machine that ties them
together over an ALPN-negotiated
h2TLS socket.🤖 Generated with Claude Code