Skip to content

Commit 6345cf2

Browse files
quaesitor-scientiamRichard Wheelerclaude
authored
net.http: enable HTTP/2 by default for https requests (#27384)
* net.http: enable HTTP/2 by default for https requests 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 (#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> * net.http: gate default-h2 network test on Windows; refresh ALPN comment 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 (#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> --------- Co-authored-by: Richard Wheeler <quaesitor.scientiam@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 35ffbab commit 6345cf2

4 files changed

Lines changed: 20 additions & 10 deletions

File tree

vlib/net/http/backend.c.v

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ fn net_ssl_do(req &Request, port int, method Method, host_name string, path stri
2121
eprint(req_headers)
2222
eprintln('')
2323
}
24-
// Advertise ALPN `h2` (with an `http/1.1` fallback) only when HTTP/2 is
25-
// requested, so existing callers see no change on the wire. The HTTP/2 read
26-
// path now feeds the same streaming callbacks and honors the stop limits,
27-
// so they no longer force HTTP/1.1.
24+
// Advertise ALPN `h2` (with an `http/1.1` fallback) when HTTP/2 is enabled.
25+
// This is the default for https requests, so ordinary get()/fetch() calls
26+
// advertise ALPN and use HTTP/2 when the server selects it; callers can opt
27+
// out with `enable_http2: false`. The HTTP/2 read path feeds the same
28+
// streaming callbacks and honors the stop limits, so they do not force
29+
// HTTP/1.1.
2830
alpn := if req.enable_http2 { ['h2', 'http/1.1'] } else { []string{} }
2931
for {
3032
mut ssl_conn := ssl.new_ssl_conn(

vlib/net/http/h2_client_test.v

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,26 @@ fn test_h2_authority_omits_default_port() {
7979
assert h2_authority('example.com', 8443) == 'example.com:8443'
8080
}
8181

82-
// Opt-in end-to-end test against a real HTTP/2 server. Run with `-d network`,
82+
// End-to-end test against a real HTTP/2 server. Run with `-d network`,
8383
// e.g. `v -d network test vlib/net/http/h2_client_test.v`.
8484
fn test_http2_fetch_real_server() {
8585
$if !network ? {
8686
return
8787
}
88-
resp := fetch(url: 'https://www.google.com/', enable_http2: true)!
88+
$if windows && !no_vschannel ? {
89+
// On Windows the default HTTPS client is SChannel, which has no ALPN
90+
// yet (vlang/v#27383), so it cannot negotiate HTTP/2. Covered with
91+
// `-d no_vschannel` (mbedtls client).
92+
eprintln('skipping: SChannel client has no ALPN/HTTP2 support yet')
93+
return
94+
}
95+
// HTTP/2 is negotiated by default for https requests.
96+
resp := get('https://www.google.com/')!
8997
assert resp.version() == .v2_0
9098
assert resp.status_code == 200
9199
assert resp.body.len > 0
92-
// Without opting in, the same server is reached over HTTP/1.1.
93-
plain := get('https://www.google.com/')!
100+
// Opting out forces HTTP/1.1 against the same server.
101+
plain := fetch(url: 'https://www.google.com/', enable_http2: false)!
94102
assert plain.version() == .v1_1
95103
}
96104

vlib/net/http/http.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub mut:
3636
in_memory_verification bool // if true, verify, cert, and cert_key are read from memory, not from a file
3737
allow_redirect bool = true // whether to allow redirect
3838
max_retries int = 5 // maximum number of retries required when an underlying socket error occurs
39-
enable_http2 bool // opt in to HTTP/2 over TLS: advertise ALPN `h2` and, if the server selects it, speak HTTP/2 instead of HTTP/1.1. on_progress / on_progress_body / stop_copying_limit / stop_receiving_limit are honored on the HTTP/2 path; on_progress fires per DATA frame payload rather than per raw network read.
39+
enable_http2 bool = true // when true (the default) and the URL is https, advertise ALPN `h2, http/1.1` and use HTTP/2 if the server selects it; set to false to force HTTP/1.1. Ignored for plain http://, and for the Windows SChannel backend which has no ALPN yet (see vlang/v#27383). on_progress / on_progress_body / stop_copying_limit / stop_receiving_limit are honored on the HTTP/2 path; on_progress fires per DATA frame payload rather than per raw network read.
4040
// callbacks to allow custom reporting code to run, while the request is running, and to implement streaming
4141
on_redirect RequestRedirectFn = unsafe { nil }
4242
on_progress RequestProgressFn = unsafe { nil }

vlib/net/http/request.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub mut:
4646
in_memory_verification bool // if true, verify, cert, and cert_key are read from memory, not from a file
4747
allow_redirect bool = true // whether to allow redirect
4848
max_retries int = 5 // maximum number of retries required when an underlying socket error occurs
49-
enable_http2 bool // opt in to HTTP/2 over TLS: advertise ALPN `h2` and, if the server selects it, speak HTTP/2 instead of HTTP/1.1. on_progress / on_progress_body / stop_copying_limit / stop_receiving_limit are honored on the HTTP/2 path; on_progress fires per DATA frame payload rather than per raw network read.
49+
enable_http2 bool = true // when true (the default) and the URL is https, advertise ALPN `h2, http/1.1` and use HTTP/2 if the server selects it; set to false to force HTTP/1.1. Ignored for plain http://, and for the Windows SChannel backend which has no ALPN yet (see vlang/v#27383). on_progress / on_progress_body / stop_copying_limit / stop_receiving_limit are honored on the HTTP/2 path; on_progress fires per DATA frame payload rather than per raw network read.
5050
// callbacks to allow custom reporting code to run, while the request is running, and to implement streaming
5151
on_redirect RequestRedirectFn = unsafe { nil }
5252
on_progress RequestProgressFn = unsafe { nil }

0 commit comments

Comments
 (0)