Skip to content

net.http: add ALPN negotiation to the Windows SChannel backend#27395

Merged
JalonSolov merged 2 commits into
vlang:masterfrom
quaesitor-scientiam:schannel-alpn
Jun 9, 2026
Merged

net.http: add ALPN negotiation to the Windows SChannel backend#27395
JalonSolov merged 2 commits into
vlang:masterfrom
quaesitor-scientiam:schannel-alpn

Conversation

@quaesitor-scientiam

Copy link
Copy Markdown
Contributor

What

First half of #27383: give the Windows SChannel (vschannel) TLS backend the ability to advertise ALPN protocols and read the protocol the server selected, bringing it to parity with the mbedtls/OpenSSL backends (ALPN landed for those in #27343; SChannel was explicitly deferred).

Why

On a default Windows build the HTTP client uses SChannel, which had no ALPN, so http.fetch(enable_http2: true) could never negotiate HTTP/2 there. This is also why the server-side HTTP/2 test (#27382) and the default-on test had to be gated with $if windows && !no_vschannel ?. This PR adds the negotiation primitive those depend on.

Changes

thirdparty/vschannel/vschannel.c

  • TlsContext gains an ALPN list to advertise and a slot for the negotiated protocol.
  • perform_client_handshake() passes a SECBUFFER_APPLICATION_PROTOCOLS input buffer (SEC_APPLICATION_PROTOCOLS / SecApplicationProtocolNegotiationExt_ALPN) into the ClientHello when a list is configured. When it is not (the default), pInput stays NULL and the handshake is byte-identical to before — existing HTTP/1.1 requests are unaffected.
  • After the handshake, SECPKG_ATTR_APPLICATION_PROTOCOL is queried and stored.
  • New entry points: vschannel_set_alpn(), vschannel_get_alpn(), vschannel_alpn_probe() (handshake-only).

vlib/net/http (Windows only)

  • vschannel_alpn_windows.c.v — exposes the C API, an alpn_wire() encoder, and schannel_alpn_probe().
  • vschannel_alpn_windows_test.v — a wire-encoding unit test plus -d network tests that probe a public HTTP/2 server and assert h2 is negotiated (and that offering only http/1.1 falls back).

Scope (deliberate)

This does not change fetch(). The one-shot vschannel request() path still speaks HTTP/1.1, so advertising h2 in real requests would let a server pick a protocol we can't yet speak. Wiring the request path to an HTTP/2 driver is the second half of #27383. This PR satisfies the issue's first acceptance criterion: a negotiated_alpn()-equivalent that works on SChannel.

Verification

Compiled and tested on real Windows (SChannel):

  • v test vlib\net\http\vschannel_alpn_windows_test.v — compiles vschannel.c with the ALPN changes; wire-encoding test passes.
  • v -d network -stats test vlib\net\http\vschannel_alpn_windows_test.vall three tests pass, including live h2 negotiation against a real HTTP/2 server and the http/1.1 fallback.

v fmt -verify clean on the V files.

Note for reviewers: the SSPI ALPN types (SEC_APPLICATION_PROTOCOLS, SECPKG_ATTR_APPLICATION_PROTOCOL, …) require a Windows 8.1+ SDK; they compiled fine with the tested toolchain. If the tcc-windows CI lacks them in its bundled headers, I'll add guarded fallback definitions.

🤖 Generated with Claude Code

@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.

Richard Wheeler and others added 2 commits June 8, 2026 17:13
First half of vlang#27383: give the SChannel (vschannel) TLS backend the
ability to advertise ALPN protocols and read the protocol the server selected,
reaching parity with the mbedtls/OpenSSL backends (vlang#27343) on the negotiation
primitive.

thirdparty/vschannel/vschannel.c:
- TlsContext gains an ALPN protocol list to advertise and a slot for the
  negotiated protocol.
- perform_client_handshake() passes a SECBUFFER_APPLICATION_PROTOCOLS input
  buffer (SEC_APPLICATION_PROTOCOLS / SecApplicationProtocolNegotiationExt_ALPN)
  into the ClientHello when a list is configured; the path is unchanged when it
  is not, so existing HTTP/1.1 requests are byte-identical.
- After the handshake, SECPKG_ATTR_APPLICATION_PROTOCOL is queried and stored.
- New C entry points: vschannel_set_alpn(), vschannel_get_alpn(), and
  vschannel_alpn_probe() (handshake-only, no application data).

vlib/net/http (Windows only):
- vschannel_alpn_windows.c.v exposes the C API, an alpn_wire() encoder, and
  schannel_alpn_probe().
- vschannel_alpn_windows_test.v: a wire-encoding unit test plus `-d network`
  tests that probe a public HTTP/2 server and assert `h2` is negotiated (and
  that offering only http/1.1 falls back).

This deliberately does NOT change fetch(): the one-shot vschannel request() path
still speaks HTTP/1.1, so advertising `h2` in real requests waits for the
HTTP/2-driver wiring (the second half of vlang#27383). It satisfies the issue's
first acceptance criterion (a negotiated_alpn()-equivalent on SChannel).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tcc bundles Windows SDK headers that predate SChannel ALPN, so the ALPN structs, enums and constants were undeclared. Define them when the SDK headers do not, matching the official layout exactly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JalonSolov JalonSolov merged commit ed17e5f into vlang:master Jun 9, 2026
80 of 86 checks passed
@quaesitor-scientiam quaesitor-scientiam deleted the schannel-alpn branch June 9, 2026 12:02
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.

3 participants