feat(std/http): upgrade a connection with 101 Switching Protocols and a Duplex #458

Merged
argus merged 3 commits from loop/74-http-upgrade-duplex into main 2026-10-24 05:49:04 +00:00
Collaborator

Closes #74

Server side of NETWORK.md slice 14 as amended in the decision comment on #74: Status.switchingProtocols, Response.upgrade(handler, headers), Upgrade and Duplex (source, sink, remote, isEncrypted) in std/http. serveConnection writes the 101 with the handler's own fields and no framing, hands the closure the connection (buffered bytes first), keeps it busy so shutdown(grace) waits and then cancels, and never reads it as HTTP again. A 101 without a closure, or a closure with another status, is answered 500. WebSocket framing stays with std/web (#105).

Tests: tests/conformance/http-upgrade.trb (cases 1 to 7) and https-upgrade.trb (a copy of the https-exchange fixture, cases 1 to 4). Written without a local compiler (builds run in CI only), so the .expected files are predicted and may need a CI round.

Status: draft until forge CI is green; the docs commit (http.md, NETWORK.md, skills/) follows.

CI: pending

Closes #74 Server side of NETWORK.md slice 14 as amended in the decision comment on #74: `Status.switchingProtocols`, `Response.upgrade(handler, headers)`, `Upgrade` and `Duplex` (source, sink, remote, isEncrypted) in `std/http`. `serveConnection` writes the `101` with the handler's own fields and no framing, hands the closure the connection (buffered bytes first), keeps it `busy` so `shutdown(grace)` waits and then cancels, and never reads it as HTTP again. A `101` without a closure, or a closure with another status, is answered `500`. WebSocket framing stays with `std/web` (#105). Tests: `tests/conformance/http-upgrade.trb` (cases 1 to 7) and `https-upgrade.trb` (a copy of the `https-exchange` fixture, cases 1 to 4). Written without a local compiler (builds run in CI only), so the `.expected` files are predicted and may need a CI round. Status: draft until forge CI is green; the docs commit (http.md, NETWORK.md, skills/) follows. CI: pending
feat(std/http): upgrade a connection with 101 Switching Protocols and a Duplex
Some checks failed
ci / commit messages (pull_request) Has been cancelled
ci / what the change touches (pull_request) Has been cancelled
ci / gates (pull_request) Has been cancelled
a44a3ff98d
docs(std/http): the upgrade in the standard-library page, NETWORK.md and skills
Some checks failed
ci / commit messages (pull_request) Successful in 4s
ci / what the change touches (pull_request) Successful in 4s
ci / the VS Code extension (editors/vscode) (pull_request) Has been skipped
pdisc / pdisc (pull_request) Successful in 10s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / bootstrap (linux-x64) (pull_request) Successful in 2m22s
ci / tier B (linux-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m44s
ci / tier A (linux-x64) (pull_request) Failing after 4m15s
ci / the playground (torb as WebAssembly) (pull_request) Failing after 2m13s
ci / every host emits the same C (pull_request) Successful in 4m44s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
6a00162135
fix(std/http): rename the upgrade field to takeover and fix the upgrade conformance tests
All checks were successful
ci / commit messages (pull_request) Successful in 4s
ci / what the change touches (pull_request) Successful in 5s
pdisc / pdisc (pull_request) Successful in 10s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 2m15s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tier B (linux-x64) (pull_request) Successful in 14m6s
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 2m31s
ci / every host emits the same C (pull_request) Successful in 4m47s
ci / tier A (linux-x64) (pull_request) Successful in 24m54s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / the playground (torb as WebAssembly) (pull_request) Successful in 2m22s
ci / gates (pull_request) Successful in 0s
5316ae6ccd
argus approved these changes 2026-10-24 05:49:03 +00:00
argus left a comment

Checklist on 5316ae6:

  • Tests: ok. http-upgrade (cases 1-7) and https-upgrade (cases 1-4) cover the head bytes, early bytes, both directions, half-close either way, a plain request beside an open upgrade, a bare 101 answered 500, and shutdown grace then cancel. CI is green on this head (bootstrap, tier A, tier B, gates, pdisc).
  • Correctness: ok. The 101/takeover mismatch check is symmetric (a bare 101 and a takeover with another status both become 500, takeover dropped). The peer watcher is cancelled and joined before the upgrade, so no read races the closure and buffered bytes stay in the connection for Duplex.source(). An undrained body closes instead of upgrading. writeUpgrade keeps the handler's Connection: Upgrade and still drops length/coding and sanitizes names and values. The connection stays busy, so shutdown waits and then cancels.
  • Scope: ok. Server side of slice 14 on #74; WebSocket framing stays in std/web.
  • Security: ok. No new ports, secrets or dependencies; header checks unchanged.
  • Docs: ok. http.md (and the skill copy) and NETWORK.md are in this diff.
  • Architecture: ok. Additive public API (Duplex, Upgrade, Response.upgrade, Status.switchingProtocols), documented in NETWORK.md.

Non-blocking:

  1. The PR body still says "draft until forge CI is green", "the docs commit follows" and "CI: pending". The docs are in the diff and CI is green.
  2. writeUpgrade always writes HTTP/1.1, also for an HTTP/1.0 request. Harmless, since 101 needs 1.1 anyway; a one-line note in the docs would settle it.
Checklist on 5316ae6: - Tests: ok. `http-upgrade` (cases 1-7) and `https-upgrade` (cases 1-4) cover the head bytes, early bytes, both directions, half-close either way, a plain request beside an open upgrade, a bare `101` answered 500, and shutdown grace then cancel. CI is green on this head (bootstrap, tier A, tier B, gates, pdisc). - Correctness: ok. The `101`/takeover mismatch check is symmetric (a bare `101` and a takeover with another status both become 500, takeover dropped). The peer watcher is cancelled and joined before the upgrade, so no read races the closure and buffered bytes stay in the connection for `Duplex.source()`. An undrained body closes instead of upgrading. `writeUpgrade` keeps the handler's `Connection: Upgrade` and still drops length/coding and sanitizes names and values. The connection stays `busy`, so shutdown waits and then cancels. - Scope: ok. Server side of slice 14 on #74; WebSocket framing stays in `std/web`. - Security: ok. No new ports, secrets or dependencies; header checks unchanged. - Docs: ok. http.md (and the skill copy) and NETWORK.md are in this diff. - Architecture: ok. Additive public API (`Duplex`, `Upgrade`, `Response.upgrade`, `Status.switchingProtocols`), documented in NETWORK.md. Non-blocking: 1. The PR body still says "draft until forge CI is green", "the docs commit follows" and "CI: pending". The docs are in the diff and CI is green. 2. `writeUpgrade` always writes `HTTP/1.1`, also for an HTTP/1.0 request. Harmless, since 101 needs 1.1 anyway; a one-line note in the docs would settle it.
argus merged commit 3575259d58 into main 2026-10-24 05:49:04 +00:00
argus deleted branch loop/74-http-upgrade-duplex 2026-10-24 05:49:04 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!458
No description provided.