Skip to content
github-actions[bot] edited this page Jul 16, 2026 · 8 revisions

HTTP/2 协议指南

HTTP/2 在 TLS 上经 ALPN h2 作为默认安全多路复用路径;同源连接池以 stream 租约复用。无 server push;h2c、后台 PING 与 per-request priority 均为显式能力。

公开入口见 HTTP 同步 / 会话配置。WebSocket 隧道见 WebSocket

结论

主题 行为
默认路径 TLS ALPN h2PreferHttp2 默认 true)
h2c opt-inSendOptions.Http2CleartextMode = PriorKnowledgeUpgrade
多流复用 同源 H2 连接承载多个活动请求;受本地与 peer MAX_CONCURRENT_STREAMS 限制
Server push 不支持;任何 PUSH_PROMISE → 协议错误
Extended CONNECT RFC 8441;wss 默认使用(见 WebSocket)
GOAWAY / RST 未处理 stream 可映射 STATUS_RETRY;仅安全方法 fresh retry 一次
后台 PING session Http2KeepAlive.Enabled 默认
Priority SendOptions.Http2Priority 显式;不维护本地依赖树调度

连接与 SETTINGS

  • 客户端发送 preface 与 SETTINGS;ENABLE_PUSH=0;立即 ACK,不阻塞等待对端 ACK。
  • 对端 ENABLE_PUSH != 0、非法窗口/帧大小、非法 ENABLE_CONNECT_PROTOCOL → 协议/流控错误。
  • 缺 ACK 且后续读超时 → GOAWAY SETTINGS_TIMEOUT
  • CONTINUATION 洪泛防护:≤64 帧、≤4 空帧(CVE-2024-27316 类)。
  • 头块累计超容量 → ENHANCE_YOUR_CALM / STATUS_BUFFER_TOO_SMALL
  • 连接专属头(connection/transfer-encoding/upgrade 等)禁止;te 仅允许 trailers

多流与 body

  • 连接池对同源 H2 做 stream 租约;帧循环按 stream id 分发 HEADERS/DATA/WINDOW_UPDATE/RST。
  • 请求 body 由 body source 驱动,按 min(连接发送窗口, 流远端窗口, peer MaxFrameSize) 切 DATA。
  • 请求 trailers:body 结束后以 trailing HEADERS + END_STREAM 发送(HTTP/2 头块,有别于 HTTP/1.1 chunked trailer);拒绝 trailer 伪头;禁止字段规则与 HTTP/1.1 对齐。
  • 流控:连接级 + per-stream;InitialWindowSize 更新同步到活动流;越界 → FLOW_CONTROL_ERROR
  • 1xx interim:拒绝 :status 101 与 interim+END_STREAM;其余 interim 重置后继续读最终响应。

RFC 8441 extended CONNECT

  • 形态::method: CONNECT + :protocol: websocket
  • 发送前要求 peer SETTINGS_ENABLE_CONNECT_PROTOCOL=1,否则 STATUS_NOT_SUPPORTED 且不分配 stream。
  • 收到 2xx 后双向 DATA 作为隧道 payload。
  • 这是 HTTP/2 隧道原语;wknet::websocketwss 默认自动选择,可用 Http11Only 强制 HTTP/1.1 Upgrade。

GOAWAY / RST 与重试

条件 高层语义
clean GOAWAY 且活动流 id > lastStreamId stream 未处理STATUS_RETRY
REFUSED_STREAM 且可证明未处理 STATUS_RETRY
GOAWAY 错误码非 0 / 其它 RST 连接断开类失败

高层仅对 安全方法GET/HEAD/OPTIONS)做 一次 fresh retry;带 body 的非幂等方法不自动重放。连接级错误广播给活动流。

h2c(默认关)

模式 要点
PriorKnowledge 明文直接 HTTP/2 preface + SETTINGS
Upgrade HTTP/1.1 Upgrade;禁止请求体;保留 stream 1,重放 101 后残留字节
默认 http:// 自动 h2c

显式非 HTTP ALPN,或设置了 HTTP/2 priority 的请求,不会选用 HTTP/3(见 HTTP/3 与 QUIC)。

Priority 与 PING

  • PrioritySendOptions.Http2Priority 在首个 HEADERS 携带 weight/dependency/exclusive(权重 1..256);拒绝自依赖。不实现复杂本地 priority tree 或带宽调度。
  • 后台 PINGSessionConfig.Http2KeepAlive.Enabled=true 显式开启;只扫描 idle 且可复用的池化 H2 连接;ACK 超时或协议错误关闭该 idle 连接。默认 idle/interval 30s,ACK 超时 5s。

HPACK(行为边界)

  • 动态表大小更新仅限块首且 ≤协商值;header-list 按 name+value+32 计。
  • 编码端对 authorization / cookie / proxy-authorization 强制 Never-Indexed
  • Huffman 拒绝过长码 / EOS / 非法 padding。

默认关闭一览

能力 开启方式
h2c SendOptions.Http2CleartextMode
后台 PING Http2KeepAlive.Enabled=true
per-request priority SendOptions.Http2Priority

支持范围见 能力边界


English

HTTP/2 Protocol Guide

HTTP/2 is the default secure multiplexed path over TLS ALPN h2. Same-origin pools reuse one connection via stream leases. Server push is unsupported; h2c, background PING, and per-request priority are explicit capabilities.

Public entry points: HTTP sync / Session config. WebSocket tunnels: WebSocket.

Summary

Topic Behavior
Default path TLS ALPN h2 (PreferHttp2 defaults true)
h2c Opt-in: SendOptions.Http2CleartextMode = PriorKnowledge or Upgrade
Multiplexing One same-origin H2 connection carries multiple active requests; limited by local and peer MAX_CONCURRENT_STREAMS
Server push Unsupported; any PUSH_PROMISE is a protocol error
Extended CONNECT RFC 8441; default for wss (see WebSocket)
GOAWAY / RST Untreated streams may map to STATUS_RETRY; safe methods get one fresh retry
Background PING Session Http2KeepAlive.Enabled defaults off
Priority Explicit SendOptions.Http2Priority; no local dependency-tree scheduler

Connection and SETTINGS

  • Client sends the preface and SETTINGS with ENABLE_PUSH=0; ACKs immediately without blocking on the peer ACK.
  • Peer ENABLE_PUSH != 0, illegal window/frame sizes, or illegal ENABLE_CONNECT_PROTOCOL → protocol/flow-control error.
  • Missing ACK plus a later read timeout → GOAWAY SETTINGS_TIMEOUT.
  • CONTINUATION flood guards: ≤64 frames, ≤4 empty frames (CVE-2024-27316 class).
  • Accumulated header block over capacity → ENHANCE_YOUR_CALM / STATUS_BUFFER_TOO_SMALL.
  • Connection-specific headers (connection/transfer-encoding/upgrade, …) are forbidden; te may only be trailers.

Streams and body

  • The pool grants stream leases on same-origin H2 connections; the frame loop demuxes HEADERS/DATA/WINDOW_UPDATE/RST by stream id.
  • Request bodies are driven by a body source and sliced into DATA under min(connection send window, stream remote window, peer MaxFrameSize).
  • Request trailers: after the body, trailing HEADERS + END_STREAM (an HTTP/2 header block, separate from HTTP/1.1 chunked trailers); trailer pseudo-headers rejected; forbidden fields align with HTTP/1.1.
  • Flow control: connection + per-stream; InitialWindowSize updates apply to active streams; overflow → FLOW_CONTROL_ERROR.
  • 1xx interim: reject :status 101 and interim+END_STREAM; other interim responses reset and continue to the final response.

RFC 8441 extended CONNECT

  • Shape: :method: CONNECT + :protocol: websocket.
  • Requires peer SETTINGS_ENABLE_CONNECT_PROTOCOL=1; otherwise STATUS_NOT_SUPPORTED and no stream is allocated.
  • After a 2xx response, bidirectional DATA carries tunnel payload.
  • This is the HTTP/2 tunnel primitive; wknet::websocket selects it by default for wss, or forces HTTP/1.1 Upgrade with Http11Only.

GOAWAY / RST and retry

Condition High-level semantics
Clean GOAWAY and active stream id > lastStreamId Stream untreatedSTATUS_RETRY
REFUSED_STREAM and provably untreated STATUS_RETRY
Non-zero GOAWAY error / other RST Connection-disconnected failure

The high-level layer performs one fresh retry only for safe methods (GET/HEAD/OPTIONS); non-idempotent methods with a body are not auto-replayed. Connection-level errors fan out to active streams.

h2c (off by default)

Mode Notes
PriorKnowledge Cleartext HTTP/2 preface + SETTINGS
Upgrade HTTP/1.1 Upgrade; no request body; reserves stream 1 and replays post-101 residual bytes
Default http:// does not auto-select h2c

Requests with an explicit non-HTTP ALPN, or with HTTP/2 priority set, do not select HTTP/3 (see HTTP/3 & QUIC).

Priority and PING

  • Priority: SendOptions.Http2Priority attaches weight/dependency/exclusive on the first HEADERS (weight 1..256); self-dependency rejected. Complex local priority-tree scheduling is not implemented.
  • Background PING: enable with SessionConfig.Http2KeepAlive.Enabled=true; only idle reusable pooled H2 connections are scanned; ACK timeout or protocol error closes that idle connection. Defaults: idle/interval 30s, ACK timeout 5s.

HPACK (behavioral bounds)

  • Dynamic-table size updates only at the start of a block and ≤ negotiated size; header-list size is name+value+32.
  • Encoder forces Never-Indexed for authorization / cookie / proxy-authorization.
  • Huffman rejects overlong codes / EOS / illegal padding.

Default-off features

Capability How to enable
h2c SendOptions.Http2CleartextMode
Background PING Http2KeepAlive.Enabled=true
Per-request priority SendOptions.Http2Priority

See the capability matrix for support scope.

Clone this wiki locally