Commit 42d99a3
authored
net.http: h2 server — close the final 7 h2spec conformance gaps (146/146) (#27627)
* net.http: h2 server — close the final 7 h2spec conformance gaps (146/146)
Flow control (RFC 9113 §6.9/§6.9.1), in handle_control_frame so both the
main dispatch and the pump_for_window stall path get the rules:
- WINDOW_UPDATE with a zero increment: connection (stream 0) -> connection
error PROTOCOL_ERROR; stream -> RST_STREAM(PROTOCOL_ERROR).
- WINDOW_UPDATE growing a flow-control window past 2^31-1: connection ->
GOAWAY(FLOW_CONTROL_ERROR); stream -> RST_STREAM(FLOW_CONTROL_ERROR).
Validate-before-mutate: the new window is computed and checked before
being committed.
SETTINGS (RFC 9113 §6.5.2):
- SETTINGS_ENABLE_PUSH accepts only 0 or 1; anything else is a connection
error PROTOCOL_ERROR.
Priority self-dependency (RFC 7540 §5.3.1, deprecated-but-validated in 9113):
- A PRIORITY frame that depends on its own stream -> RST_STREAM(PROTOCOL_ERROR),
sent at most once per id (locally_reset guard - no second RST on a stream
we already reset).
- A HEADERS frame (opening or trailer) whose priority section depends on its
own stream: the block is still HPACK-decoded first (RFC 7541 §2.2 - the
decoder is stateful), then the stream is reset with PROTOCOL_ERROR, via a
self_dep flag mirroring the refused/over_end decode-then-RST pattern.
With these, the server passes ALL 146 h2spec v2.6.0 cases (verified 5/5
deterministic runs at --timeout 5, plus 1 run after each review fix); the
expected-failures baseline is now EMPTY, so CI fails on any h2spec failure.
Tests: 9 new scripted-peer cases in h2_server_test.v (zero-increment
conn/stream, overflow conn/stream, ENABLE_PUSH=2, HEADERS/PRIORITY/trailer
self-dependency, repeated-PRIORITY single-RST). Full vlib/net/http suite
green (23 passed, 2 skipped).
* fix(h2): classify_stream must treat locally_reset ids as closed; sync h2spec docs
RFC 9113 §5.1 defines "closed" as entered when either side sends RST_STREAM,
and explicitly permits remembering a reset stream in that state for a bounded
period (exactly what the locally_reset FIFO already implements). classify_stream
only tested `stream_id & 1 == 1 && stream_id <= last_stream_id`, which misses any
id we RST'd without it ever having advanced last_stream_id — a self-dependent
PRIORITY frame (RFC 7540 §5.3.1) is legal on a stream the client never opened via
HEADERS, so it can be locally_reset while last_stream_id still hasn't counted it.
Consequence: an in-flight DATA/WINDOW_UPDATE/RST_STREAM for such an id, arriving
after our RST but classified via the old rule, was misread as a frame on an IDLE
stream (a connection PROTOCOL_ERROR) instead of drained per §6.4 — a spurious
GOAWAY on legitimate late traffic.
Fix: classify_stream checks c.locally_reset before the parity/last_stream_id
test, so every caller (on_data, handle_control_frame's WINDOW_UPDATE arm,
dispatch_frame's RST_STREAM arm) gets the correct closed/drain behavior from one
place, rather than three duplicated per-branch checks that a future fourth
caller could silently miss.
Also syncs vlib/net/http/h2spec/{README.md,run_h2spec.sh} — both still described
the pre-#27627 37-case baseline; the baseline has been empty (146/146) since
#27627.
Both from Codex, #27627 pullrequestreview-4618166175.
* fix(h2): tighten h2spec README wording after conformance-doc sync
Three follow-ups from Codex review 4619906229 on the prior doc-sync commit:
- the replaced h2spec_expected_failures.txt table row was 193 chars, over the
repo's 100-char markdown line limit — shortened.
- "Four follow-up PRs" listed only three PR numbers (#27569, #27589, #27627) —
corrected to "Three".
- the empty-baseline statement conflicted with unchanged bullets below still
describing "genuine conformance gaps" and instructing removal of lines as
cases are fixed — reworded to note the baseline is currently empty while the
tracking mechanism stays in place for future gaps.
Doc-only change; verified with ./vnew check-md (0 errors) and a line-length scan.
Both from Codex, #27627 pullrequestreview-4619906229.
* fix(h2): self-dependent PRIORITY must not re-RST an already-closed stream
The self-dependency guard for PRIORITY frames (RFC 7540 §5.3.1) exempted only
`frame.stream_id in c.locally_reset` from re-sending RST_STREAM. That misses a
stream that completed NORMALLY: run_request deletes it from c.streams without
ever touching locally_reset, so classify_stream already correctly reports it
as closed, but the old check saw "not locally_reset" and sent a fresh
RST_STREAM anyway — itself a frame-on-a-closed-stream violation (RFC 9113
§5.1), since PRIORITY is permitted on closed streams but RST_STREAM is not.
Fix: gate on `c.classify_stream(frame.stream_id) != .closed` instead of the
locally_reset-only check. idle and active streams still get RST_STREAM
(self-dependency remains a stream error per §5.3.1 regardless of whether the
stream was ever opened); any already-closed stream — whether closed via
locally_reset or via normal completion — is left alone. This reuses the same
classify_stream generalization from the prior commit rather than adding a
second ad-hoc exemption, so a future caller of this guard inherits the correct
behavior automatically.
Codex, #27627 pullrequestreview-4620220448.
* fix(h2): self-dependent HEADERS over the concurrency limit must be PROTOCOL_ERROR
finalize_headers checked s.refused (RFC 9113 §5.1.2, over the concurrency
limit) before s.self_dep (RFC 7540 §5.3.1, priority self-dependency). A
HEADERS frame that was both over-limit and self-dependent therefore answered
RST_STREAM(REFUSED_STREAM) instead of PROTOCOL_ERROR.
REFUSED_STREAM specifically tells the client the request is safe to retry
unchanged elsewhere; a self-dependent request is malformed independent of the
concurrency limit, so retrying it verbatim would just repeat the same error.
Fix: swap the check order so self_dep is evaluated first — both branches
still route through the identical decode-then-RST pattern (HPACK block
already decoded above for dynamic-table sync), so there is no HPACK
regression, only the reported error code changes.
Codex, #27627 pullrequestreview-4620412384.1 parent d21e26c commit 42d99a3
5 files changed
Lines changed: 520 additions & 40 deletions
File tree
- vlib/net/http
- h2spec
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
172 | 172 | | |
173 | 173 | | |
174 | 174 | | |
| 175 | + | |
175 | 176 | | |
176 | 177 | | |
177 | 178 | | |
| |||
233 | 234 | | |
234 | 235 | | |
235 | 236 | | |
236 | | - | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
237 | 242 | | |
238 | 243 | | |
239 | 244 | | |
| |||
251 | 256 | | |
252 | 257 | | |
253 | 258 | | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
254 | 270 | | |
255 | 271 | | |
256 | 272 | | |
| |||
372 | 388 | | |
373 | 389 | | |
374 | 390 | | |
375 | | - | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
376 | 403 | | |
377 | 404 | | |
378 | 405 | | |
| |||
417 | 444 | | |
418 | 445 | | |
419 | 446 | | |
| 447 | + | |
420 | 448 | | |
421 | | - | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
422 | 463 | | |
423 | | - | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
424 | 481 | | |
425 | 482 | | |
426 | 483 | | |
| |||
442 | 499 | | |
443 | 500 | | |
444 | 501 | | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
445 | 507 | | |
446 | 508 | | |
447 | 509 | | |
| |||
540 | 602 | | |
541 | 603 | | |
542 | 604 | | |
| 605 | + | |
543 | 606 | | |
544 | 607 | | |
545 | 608 | | |
| |||
615 | 678 | | |
616 | 679 | | |
617 | 680 | | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
618 | 694 | | |
619 | 695 | | |
620 | 696 | | |
| |||
645 | 721 | | |
646 | 722 | | |
647 | 723 | | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
648 | 728 | | |
649 | 729 | | |
650 | 730 | | |
| |||
670 | 750 | | |
671 | 751 | | |
672 | 752 | | |
673 | | - | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
674 | 757 | | |
675 | 758 | | |
676 | 759 | | |
| |||
0 commit comments