You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add HTTP/3 support to net.http, built on a new QUIC transport implementation
(vlib/net/quic/). This tracks a large, multi-phase effort matching the existing
HTTP/1.1 + HTTP/2 quality bar (connection pooling, conformance testing) already
in the repo, targeting Linux, Windows, and macOS.
Why a new TLS 1.3 handshake instead of using vendored mbedTLS
QUIC (RFC 9001) needs per-encryption-level secret export (Initial/Handshake/
1-RTT) and a way to carry TLS handshake bytes over QUIC CRYPTO frames instead of
a normal TLS record layer/socket.
The vendored mbedTLS (3.6.6) has no QUIC support at all — confirmed by
reading the vendored source (only the generic mbedtls_ssl_set_export_keys_cb
exists; there is no record-layer bypass and no way to carry the quic_transport_parameters extension). This isn't specific to our vendored
version: it's a long-standing, unresolved upstream limitation
(Mbed-TLS/mbedtls#6178, #4731). For comparison, ngtcp2 (the reference QUIC implementation) supports OpenSSL, LibreSSL,
GnuTLS, BoringSSL, AWS-LC, picotls, and wolfSSL as TLS backends — mbedTLS is
absent from that list for exactly this reason.
Patching mbedTLS ourselves to add the missing hooks was estimated at
~1150–2200 LOC inside the library's most actively-maintained, most complex
files (ssl_tls13_client.c/ssl_tls13_server.c), with real ongoing rebase risk
against every upstream mbedTLS release.
Decision: implement a QUIC-scoped TLS 1.3 handshake (RFC 8446) from scratch in
pure V, reusing already-existing, already-tested V crypto (X25519 ECDH,
Ed25519, HKDF, AES-GCM, SHA-256), and delegating only X.509 parsing/chain
validation to mbedTLS's already-bound C functions — the same thing HTTP/1.1 and
HTTP/2 already do today, with no mbedTLS source patch required. This lands at
comparable total LOC (~1500–3000) to patching mbedTLS, but as fully-owned V code
with no upstream-rebase risk.
Scope for v1 (open to discussion)
Client first. Server support is designed for (a role field on the core
connection struct) but out of v1's committed scope — a client can be
validated immediately against real-world QUIC servers/reference
implementations; a server can't be meaningfully tested without a working
client first.
Congestion control: NewReno (RFC 9002 Appendix B's own reference
pseudocode) rather than CUBIC — directly derivable from spec text.
0-RTT deferred — anti-replay, session resumption, and a 4th encryption
level's key derivation aren't needed for a correct 1-RTT-only handshake.
Single-threaded, caller-driven event loop per QUIC connection (library
owns state; caller calls poll()/process_timeouts(), mirroring how
quiche/ngtcp2 expose themselves as libraries) — fits V's lack of a native
async runtime and QUIC's one-UDP-socket-many-connections-by-CID model.
Phase plan
Cross-platform build risk — confirm OpenSSL (needed for new P-256 ECDH +
RSA-PSS bindings) and standalone mbedTLS X.509 usage build/work identically
on Linux/Windows/macOS before any protocol code lands. (Windows CI already
builds+tests crypto.ecdsa against OpenSSL via windows_ci_gcc.yml —
confirmed, no new CI needed there.)
Primitives — QUIC varint (RFC 9000 §16, distinct from existing LEB128),
packet number encode/decode (§17.1 + Appendix A), long/short header
parsing, new P-256 ECDH binding, new RSA-PSS module (no RSA exists in V
today).
QUIC-scoped TLS 1.3 handshake + key schedule — Initial secrets (RFC 9001
§5.2), RFC 8446 §7.1 key schedule, handshake message construction/parsing, quic_transport_parameters extension, client state machine. Includes
authoring an RFC-8448-style test vector suite from scratch (RFC 8448 itself
doesn't cover QUIC's no-record-layer variant).
Initial packet exchange — CRYPTO frame reassembly, core frame types,
datagram coalescing, Retry and Version Negotiation handling.
Full handshake completion — three independent packet number spaces,
handshake complete vs. confirmed states, key discard, key update (RFC 9001
§6).
Stream layer — STREAM frames, stream states, connection- and
stream-level flow control interplay (RFC 9000 §2-4).
Loss detection & NewReno congestion control (RFC 9002) — RTT estimation,
packet/time threshold loss detection, PTO, persistent congestion.
Connection lifecycle — idle timeout, CONNECTION_CLOSE, stateless reset,
ECN fallback behavior, PMTU (pinned to the 1200-byte safe minimum for v1).
QuicConn — the top-level connection struct tying everything together,
with the poll()/process_timeouts() event-loop contract.
HTTP/3 framing (RFC 9114) — incremental/resumable frame parsing (a
structural difference from HTTP/2's single-shot framing, since H3 frames
ride inside QUIC STREAM frames).
QPACK (RFC 9204) — static/dynamic tables with absolute indexing,
encoder/decoder streams, blocked-stream handling.
HTTP/3 client wiring — integration into the existing Request/Response/Transport types.
(Follow-up, not v1) Server support.
(Follow-up, not v1) 0-RTT.
Validation plan
Unit tests per new file (matching the existing h2_frame_test.v-style
convention), covering the edge cases enumerated per phase (varint boundary
values, packet-number reconstruction, coalesced-packet splitting, blocked
QPACK streams, persistent congestion, etc.)
A from-scratch TLS 1.3 test vector suite (Phase 2), captured from a reference
implementation via QUIC key-log export, cross-derived independently before
being trusted as a fixture.
Interop testing: a local vlib/net/quic/interop/ harness (mirroring the
existing h2spec/ directory's shape) pinned against one reference
implementation (ngtcp2+nghttp3 or quiche), plus optional smoke tests against
public HTTP/3 endpoints and, longer-term, registering with the QUIC working
group's quic-interop-runner matrix.
Fuzzing of every parser that consumes attacker-controlled bytes before
authentication completes (header parsing, packet/header protection, frame
parsing, TLS 1.3 message parsing).
Critical new/modified files
vlib/net/quic/conn.v — architectural center (QuicConn)
vlib/net/quic/tls13_handshake.v — the TLS 1.3 state machine
vlib/net/http/transport.v (modified — HTTP/3 pool + dispatch integration)
This is a large effort intended to be delivered incrementally across many PRs,
one phase (or sub-phase) at a time, each independently tested. Feedback on the
TLS approach and v1 scope decisions above is very welcome before implementation
goes further.
Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.
Summary
Add HTTP/3 support to
net.http, built on a new QUIC transport implementation(
vlib/net/quic/). This tracks a large, multi-phase effort matching the existingHTTP/1.1 + HTTP/2 quality bar (connection pooling, conformance testing) already
in the repo, targeting Linux, Windows, and macOS.
Why a new TLS 1.3 handshake instead of using vendored mbedTLS
QUIC (RFC 9001) needs per-encryption-level secret export (Initial/Handshake/
1-RTT) and a way to carry TLS handshake bytes over QUIC CRYPTO frames instead of
a normal TLS record layer/socket.
The vendored mbedTLS (3.6.6) has no QUIC support at all — confirmed by
reading the vendored source (only the generic
mbedtls_ssl_set_export_keys_cbexists; there is no record-layer bypass and no way to carry the
quic_transport_parametersextension). This isn't specific to our vendoredversion: it's a long-standing, unresolved upstream limitation
(Mbed-TLS/mbedtls#6178,
#4731). For comparison,
ngtcp2(the reference QUIC implementation) supports OpenSSL, LibreSSL,GnuTLS, BoringSSL, AWS-LC, picotls, and wolfSSL as TLS backends — mbedTLS is
absent from that list for exactly this reason.
Patching mbedTLS ourselves to add the missing hooks was estimated at
~1150–2200 LOC inside the library's most actively-maintained, most complex
files (
ssl_tls13_client.c/ssl_tls13_server.c), with real ongoing rebase riskagainst every upstream mbedTLS release.
Decision: implement a QUIC-scoped TLS 1.3 handshake (RFC 8446) from scratch in
pure V, reusing already-existing, already-tested V crypto (X25519 ECDH,
Ed25519, HKDF, AES-GCM, SHA-256), and delegating only X.509 parsing/chain
validation to mbedTLS's already-bound C functions — the same thing HTTP/1.1 and
HTTP/2 already do today, with no mbedTLS source patch required. This lands at
comparable total LOC (~1500–3000) to patching mbedTLS, but as fully-owned V code
with no upstream-rebase risk.
Scope for v1 (open to discussion)
rolefield on the coreconnection struct) but out of v1's committed scope — a client can be
validated immediately against real-world QUIC servers/reference
implementations; a server can't be meaningfully tested without a working
client first.
pseudocode) rather than CUBIC — directly derivable from spec text.
level's key derivation aren't needed for a correct 1-RTT-only handshake.
owns state; caller calls
poll()/process_timeouts(), mirroring howquiche/ngtcp2 expose themselves as libraries) — fits V's lack of a native
async runtime and QUIC's one-UDP-socket-many-connections-by-CID model.
Phase plan
RSA-PSS bindings) and standalone mbedTLS X.509 usage build/work identically
on Linux/Windows/macOS before any protocol code lands. (Windows CI already
builds+tests
crypto.ecdsaagainst OpenSSL viawindows_ci_gcc.yml—confirmed, no new CI needed there.)
packet number encode/decode (§17.1 + Appendix A), long/short header
parsing, new P-256 ECDH binding, new RSA-PSS module (no RSA exists in V
today).
§5.2), RFC 8446 §7.1 key schedule, handshake message construction/parsing,
quic_transport_parametersextension, client state machine. Includesauthoring an RFC-8448-style test vector suite from scratch (RFC 8448 itself
doesn't cover QUIC's no-record-layer variant).
protection masking, correct encrypt-then-mask ordering.
datagram coalescing, Retry and Version Negotiation handling.
handshake complete vs. confirmed states, key discard, key update (RFC 9001
§6).
stream-level flow control interplay (RFC 9000 §2-4).
packet/time threshold loss detection, PTO, persistent congestion.
ECN fallback behavior, PMTU (pinned to the 1200-byte safe minimum for v1).
QuicConn— the top-level connection struct tying everything together,with the
poll()/process_timeouts()event-loop contract.structural difference from HTTP/2's single-shot framing, since H3 frames
ride inside QUIC STREAM frames).
encoder/decoder streams, blocked-stream handling.
Request/Response/Transporttypes.Validation plan
h2_frame_test.v-styleconvention), covering the edge cases enumerated per phase (varint boundary
values, packet-number reconstruction, coalesced-packet splitting, blocked
QPACK streams, persistent congestion, etc.)
implementation via QUIC key-log export, cross-derived independently before
being trusted as a fixture.
vlib/net/quic/interop/harness (mirroring theexisting
h2spec/directory's shape) pinned against one referenceimplementation (ngtcp2+nghttp3 or quiche), plus optional smoke tests against
public HTTP/3 endpoints and, longer-term, registering with the QUIC working
group's
quic-interop-runnermatrix.authentication completes (header parsing, packet/header protection, frame
parsing, TLS 1.3 message parsing).
Critical new/modified files
vlib/net/quic/conn.v— architectural center (QuicConn)vlib/net/quic/tls13_handshake.v— the TLS 1.3 state machinevlib/net/quic/packet_protection.v/header_protection.vvlib/crypto/ecdsa/ecdsa.c.v(modified — new P-256 ECDH binding)vlib/net/mbedtls/mbedtls.c.v(modified — standalone X.509-only usage)vlib/net/http/transport.v(modified — HTTP/3 pool + dispatch integration)This is a large effort intended to be delivered incrementally across many PRs,
one phase (or sub-phase) at a time, each independently tested. Feedback on the
TLS approach and v1 scope decisions above is very welcome before implementation
goes further.
Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.