Skip to content

net.http: enable HTTP/2 by default for https requests#27384

Merged
JalonSolov merged 2 commits into
vlang:masterfrom
quaesitor-scientiam:net-http2-default-on
Jun 8, 2026
Merged

net.http: enable HTTP/2 by default for https requests#27384
JalonSolov merged 2 commits into
vlang:masterfrom
quaesitor-scientiam:net-http2-default-on

Conversation

@quaesitor-scientiam

Copy link
Copy Markdown
Contributor

What

Flips the enable_http2 default (on Request and FetchConfig) from false
to true, so http.fetch / http.get to an https:// URL negotiate HTTP/2
when the server offers it
, and fall back to HTTP/1.1 otherwise. To force
HTTP/1.1, set enable_http2: false.

resp := http.get('https://example.com/')        // HTTP/2 if the server supports it
resp.version() // .v2_0 on most modern servers, .v1_1 otherwise

forced := http.fetch(url: 'https://example.com/', enable_http2: false)! // always HTTP/1.1

This is the opt-out counterpart to the opt-in support added in #27362, now that
the HTTP/2 client also handles redirects, streaming callbacks (#27369), and flow
control, and has been exercised against real servers.

Scope

The change is three lines (the two field defaults + the doc) plus a test update.

File Change
request.v, http.v enable_http2 boolenable_http2 bool = true, with updated docs
h2_client_test.v the gated real-server test now asserts a default get() negotiates HTTP/2 and that enable_http2: false forces HTTP/1.1

Behaviour / compatibility

  • Unaffected: plain http:// (no ALPN, never HTTP/2), and the Windows
    SChannel backend, which has no ALPN yet and stays on HTTP/1.1 (tracked in
    net.http: add ALPN (and HTTP/2) support to the Windows SChannel TLS backend #27383).
  • No latency regression: the client sends the connection preface, its
    SETTINGS, and the request together without waiting for the server's SETTINGS,
    so there's no added round trip; HPACK also shrinks request headers.
  • Transparent fallback: advertising h2, http/1.1 is safe — servers that
    don't understand ALPN simply ignore it and the client uses HTTP/1.1.

Honest tradeoff for the maintainer to weigh

Each fetch is still one connection / one request (no pooling or
multiplexing yet), so HTTP/2's headline win — multiplexing many requests over
one connection — doesn't yet materialize. This PR is purely about defaulting to
the newer protocol; pooling/multiplexing is a planned follow-up. If you'd rather
keep HTTP/2 opt-in until pooling lands, this PR can simply wait — the opt-in
path (#27362) already works.

Tests

  • Full vlib/net/http suite green (mbedtls; 1 Windows-only skip).
  • The existing real-network HTTPS test suite (http_httpbin_test.v:
    GET/POST/PUT/PATCH/DELETE/HEAD against a live server) passes through the new
    default HTTP/2 path unchanged.
  • -d network test confirms a default get('https://www.google.com/')
    returns HTTP/2.0, and enable_http2: false returns HTTP/1.1.
  • -W -cstrict -cc clang clean.

🤖 Generated with Claude Code

Flip the `enable_http2` default on Request and FetchConfig from false to true,
so https requests made with http.fetch / http.get negotiate HTTP/2 when the
server offers it (ALPN `h2`), and transparently fall back to HTTP/1.1 otherwise.
Set `enable_http2: false` to force HTTP/1.1.

This is opt-out rather than opt-in now that the HTTP/2 client supports
redirects, streaming response callbacks, and flow control, and has been
exercised against real servers. Plain http:// is unaffected (no ALPN), and the
Windows SChannel backend keeps using HTTP/1.1 until it gains ALPN (vlang#27383).

Updates the gated real-server test to assert the new default (a plain get()
negotiates HTTP/2) and that `enable_http2: false` still forces HTTP/1.1.

Notes for review:
- No latency regression: the client sends the preface, SETTINGS, and the
  request together without waiting for the server's SETTINGS, so there is no
  extra round trip; HPACK also shrinks request headers.
- Each fetch is still one connection / one request (no pooling yet), so the
  multiplexing win does not yet apply; this change is about defaulting to the
  newer protocol, with pooling/multiplexing as a follow-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.

@quaesitor-scientiam

quaesitor-scientiam commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

• Codex Review Findings

  • Medium: The updated -d network test will fail on default Windows builds. get('https://www.google.com/') at vlib/net/http/
    h2_client_test.v:89 now expects .v2_0, but Windows still routes HTTPS through SChannel at vlib/net/http/backend.c.v:10. That backend
    builds a plain HTTP/1.1 request and has no ALPN/HTTP/2 path at vlib/net/http/backend_vschannel_windows.c.v:21. The test needs a Windows/
    no_vschannel gate or the SChannel path needs HTTP/2 support.

  • Low: The comment in vlib/net/http/backend.c.v:24 is now stale: it says ALPN is advertised “only when HTTP/2 is requested” so existing
    callers see no wire change. With enable_http2 defaulting to true, ordinary get()/fetch() calls now advertise ALPN on non-SChannel HTTPS.

Tests Run

  • .\vnew.exe test vlib\net\http\h2_client_test.v passed; the -d network block was skipped.
  • .\vnew.exe fmt -verify vlib\net\http\http.v vlib\net\http\request.v vlib\net\http\h2_client_test.v passed.
  • git diff --check master...HEAD passed.

Address review feedback on enabling HTTP/2 by default:

- test_http2_fetch_real_server now skips on the default Windows/SChannel
  configuration (`$if windows && !no_vschannel ?`), since SChannel has no ALPN
  yet (vlang#27383) and a default get() there stays on HTTP/1.1. The path remains
  covered with `-d no_vschannel` (mbedtls client).
- Refresh the now-stale comment in backend.c.v: with enable_http2 defaulting to
  true, ordinary get()/fetch() calls advertise ALPN and use HTTP/2 when the
  server selects it (opt out with enable_http2: false).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@quaesitor-scientiam

Copy link
Copy Markdown
Contributor Author

Both addressed in fa3d8c1:

Medium (Windows network test): test_http2_fetch_real_server now skips on the default Windows/SChannel configuration ($if windows && !no_vschannel ?), since SChannel has no ALPN yet (#27383) so a default get() there stays on HTTP/1.1. Still covered with -d no_vschannel (mbedtls client).

Low (stale comment): Updated the comment in backend.c.v — it no longer claims "no change on the wire"; it now notes that with enable_http2 defaulting to true, ordinary get()/fetch() advertise ALPN and use HTTP/2 when the server selects it, with opt-out via enable_http2: false.

Verified: full vlib/net/http suite green; -d network test passes (non-Windows); fmt -verify clean.

@JalonSolov JalonSolov merged commit 6345cf2 into vlang:master Jun 8, 2026
78 of 87 checks passed
JalonSolov pushed a commit that referenced this pull request Jun 8, 2026
…27393)

test_server_tls_h2_negotiation asserted that a plain `http.fetch()` (no
`enable_http2` field) is served as HTTP/1.1. That held before #27384, but
#27384 flipped `enable_http2` to default `true`, so the client now advertises
`h2` ALPN by default and the server correctly upgrades — making the test's
`resp_h1.version() == .v1_1` assertion fail. This is currently red on master
CI (clang/gcc/tcc-linux, clang-macos).

The server behavior is correct; the test just needs to opt out explicitly.
Pass `enable_http2: false` on the HTTP/1.1 leg, which is what the test means
to exercise (server still serves h1 to a client that does not negotiate h2).

Co-authored-by: Richard Wheeler <quaesitor.scientiam@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants