Repository navigation
fix(js/net): end IETF requests once through RequestStream; close the session on data after TRACK - #7355
Conversation
Quest-Claim: 768d992a7bb5df38
…the session on data after TRACK A request's Deadline now resets the RequestStream that owns its stream rather than the raw stream, so a timeout ends the request through the same closer as abandonment and errors, and the caller's later cleanup is a no-op. SUBSCRIBE's cleanup drops the sent/torn guards left from the draft 14-16 UNSUBSCRIBE path. Bytes after a lite TRACK (0x6) request now close the session with PROTOCOL_VIOLATION, as in Rust. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 2 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 10eba93.
No actionable defects found. Routing deadline failures through the existing RequestStream owner is a focused simplification that preserves raw-stream callers. The owner is established before the late-failure check, and its synchronous closed flag makes subsequent cleanup idempotent. SUBSCRIBE retains cancellation checks around setup and acceptance, repeated alias/fill retirement, and clean refusal handling. TRACK trailing bytes now use the established session-violation path while ordinary FIN/reset handling remains intact.
The new tests target reset-once behavior and malformed TRACK closure. A useful nonblocking addition would resolve an opening stream only after its deadline expires and assert that the wrapped owner aborts it exactly once without sending the request.
GitHub-only static review of all nine changed files and relevant setup, cleanup, request-owner, and existing regression-test context. No tests, builds, browser transport checks, or interoperability runs were executed; reported local results were not independently verified.
(Written by OpenAI)
|
Merge summary for head
(Written by Opus 5.5) |
|
quest land removed this pull request from the queue: the batch check failed (exit 100). Checking http-cache v1.0.0-alpha.8
Checking pipewire v0.10.1
Compiling proc-macro2-diagnostics v0.10.1
Checking moq-sock v0.2.0 (/work/rs/moq-sock)
Checking fs-err v3.3.1
Checking p384 v0.14.0
Checking p256 v0.14.0
Checking arboard v3.7.0
Checking reqwest-middleware v0.5.2
Checking web-transport-trait v0.5.2
Checking moq-auth v0.2.1 (/work/rs/moq-auth)
Checking axum v0.8.9
Checking axum-server v0.8.0
Checking egui-wgpu v0.36.2
Checking http-cache-reqwest v1.0.0-alpha.9
Checking egui-winit v0.36.2
Compiling duplicate v2.0.1
Checking eframe v0.36.2
Checking egui_dock v0.21.1
Checking cpal v0.18.2
Checking moq-json v0.5.8 (/work/rs/moq-json)
Checking moq-loc v0.2.19 (/work/rs/moq-loc)
Checking qmux v0.7.0 (/work/rs/qmux)
Checking hang v0.21.11 (/work/rs/hang)
Checking moq-stats v0.2.12 (/work/rs/moq-stats)
Checking moq-tokio v0.19.23 (/work/rs/moq-tokio)
Checking moq-mux v0.10.11 (/work/rs/moq-mux)
Checking moq-relay v0.17.2 (/work/rs/moq-relay)
Checking moq-audio v0.1.10 (/work/rs/moq-audio)
Checking moq-scene v0.1.0 (/work/rs/moq-scene)
Checking moq-studio v0.1.0 (/work/rs/moq-studio)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 07s
info: running `cargo clippy --locked --tests --all-features -- -D warnings` on moq-wasm (50/51)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
info: running `cargo clippy --locked --tests --all-features -- -D warnings` on uniffi-bindgen (51/51)
Compiling getrandom v0.4.3
Compiling winnow v1.0.4
Compiling uniffi_internal_macros v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling serde v1.0.229
Compiling libc v0.2.191
Checking indexmap v2.14.2
Compiling fs-err v3.3.1
Compiling askama_parser v0.16.1
Compiling basic-toml v0.1.10
Checking nom v7.1.3
Compiling scroll_derive v0.12.1
Checking tempfile v3.27.0
Checking smawk v0.3.3
Compiling askama_derive v0.16.1
Checking serde_json v1.0.154
Checking weedle2 v5.0.0 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling toml_parser v1.1.3+spec-1.1.0
Checking textwrap v0.16.4
Checking uniffi_pipeline v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking scroll v0.12.0
Checking uniffi_meta v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling askama_macros v0.16.1
Compiling toml_datetime v1.1.1+spec-1.1.0
Checking plain v0.2.3
Compiling toml v1.1.6+spec-1.1.0
Checking clap_builder v4.6.7
Checking uniffi_udl v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking goblin v0.8.2
Checking cargo_metadata v0.23.1
Checking askama v0.16.1
Checking uniffi_core v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking clap v4.6.7
Checking uniffi_bindgen v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling uniffi_macros v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking uniffi v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking uniffi-bindgen v0.1.0 (/work/rs/uniffi-bindgen)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.79s
mbx[cache]: object cache: 1219 hits, 0 misses, 209 not looked up; 0 B downloaded, 0 B uploaded, 408.1 MiB stored locally
mbx[cache]: 10m 13s session; 17m 18s estimated compiler time avoided (summed across compilations)
mbx[cache]: 209 compilations had no usable prior inputs or matching prediction for a lookup
mbx[cache]: Cargo artifact reuse and CI cache archive transfers are not included above
mbx[savings]: 2.3 TiB in every checkout, 2.3 TiB on disk. arithmetic declined to comment.
ci: test rs failed
ci: seconds per module
614 check rs
307 test rs (failed)
1262 check rs_shapes
237 check js
46 test js
14 check markdown
3 check gh
48 test gh
66 check flake
0 check drill
5 check quest
9 check ts_paths
21 check shell
1 check large_files
0 check toml
1 check nix
0 check justfile
2183 wall time
error: recipe `ci` failed on line 104 with exit code 100
. |
|
Codex land fixer: moq-doc:check | (pass) tables render as tables > draft-lcurley-moq-timestamp [5.56ms] moq-doc:check | (pass) tables render as tables > draft-lcurley-moq-use-cases [10.60ms] moq-doc:check | (pass) tables render as tables > draft-lcurley-qmux-websocket [5.88ms] moq-doc:check | (pass) tables render as tables > row separators do not split a table apart [54.24ms] moq-doc:check | moq-doc:check | .vitepress/api/index.test.ts: moq-doc:check | (pass) a rendered workspace > each entrypoint gets a page named by its import specifier [6.76ms] moq-doc:check | (pass) a rendered workspace > a re-export from another workspace package links to its owner [6.54ms] moq-doc:check | (pass) a rendered workspace > an external re-export is documented under each public name [29.59ms] moq-doc:check | (pass) a rendered workspace > a namespace export keeps its public name [2.52ms] moq-doc:check | (pass) a rendered workspace > a hidden declaration is documented under the alias that re-exports it [2.59ms] moq-doc:check | �[93m[warning]�[0m Value, defined in @test/hidden/src/access.ts, is referenced by read but not included in the documentation moq-doc:check | �[93m[warning]�[0m Value, defined in @test/hidden/src/access.ts, is referenced by read but not included in the documentation moq-doc:check | (pass) an unexported declaration that a public one names fails the run [381.26ms] moq-doc:check | �[93m[warning]�[0m Failed to resolve link to "Missing" in comment for value moq-doc:check | (pass) a link that does not resolve fails the run [324.62ms] moq-doc:check | moq-doc:check | concept/audio-jitter/corpus.test.ts: moq-doc:check | (pass) audio jitter corpus > paced > matches the checked-in file [0.20ms] moq-doc:check | (pass) audio jitter corpus > paced > is a trace of equal-length clocks [0.03ms] moq-doc:check | (pass) audio jitter corpus > paced > arrives in a monotonic order [0.76ms] moq-doc:check | (pass) audio jitter corpus > paced > names a target for the first frame [0.02ms] moq-doc:check | (pass) audio jitter corpus > paced > reports every target as a change [0.08ms] moq-doc:check | (pass) audio jitter corpus > flush > matches the checked-in file [0.03ms] moq-doc:check | (pass) audio jitter corpus > flush > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > flush > arrives in a monotonic order [0.16ms] moq-doc:check | (pass) audio jitter corpus > flush > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > flush > reports every target as a change moq-doc:check | (pass) audio jitter corpus > advertised > matches the checked-in file [0.03ms] moq-doc:check | (pass) audio jitter corpus > advertised > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > advertised > arrives in a monotonic order [0.16ms] moq-doc:check | (pass) audio jitter corpus > advertised > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > advertised > reports every target as a change moq-doc:check | (pass) audio jitter corpus > buildup > matches the checked-in file [0.04ms] moq-doc:check | (pass) audio jitter corpus > buildup > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > buildup > arrives in a monotonic order [0.24ms] moq-doc:check | (pass) audio jitter corpus > buildup > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > buildup > reports every target as a change [0.01ms] moq-doc:check | (pass) audio jitter corpus > reorder > matches the checked-in file [0.03ms] moq-doc:check | (pass) audio jitter corpus > reorder > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > reorder > arrives in a monotonic order [0.13ms] moq-doc:check | (pass) audio jitter corpus > reorder > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > reorder > reports every target as a change moq-doc:check | (pass) audio jitter corpus > backlog > matches the checked-in file [0.05ms] moq-doc:check | (pass) audio jitter corpus > backlog > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > backlog > arrives in a monotonic order [0.29ms] moq-doc:check | (pass) audio jitter corpus > backlog > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > backlog > reports every target as a change moq-doc:check | (pass) audio jitter corpus > idle > matches the checked-in file [0.03ms] moq-doc:check | (pass) audio jitter corpus > idle > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > idle > arrives in a monotonic order [0.13ms] moq-doc:check | (pass) audio jitter corpus > idle > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > idle > reports every target as a change moq-doc:check | (pass) audio jitter corpus > tunein > matches the checked-in file [0.04ms] moq-doc:check | (pass) audio jitter corpus > tunein > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > tunein > arrives in a monotonic order [0.19ms] moq-doc:check | (pass) audio jitter corpus > tunein > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > tunein > reports every target as a change moq-doc:check | (pass) audio jitter corpus > spike > matches the checked-in file [0.07ms] moq-doc:check | (pass) audio jitter corpus > spike > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > spike > arrives in a monotonic order [0.33ms] moq-doc:check | (pass) audio jitter corpus > spike > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > spike > reports every target as a change moq-doc:check | (pass) audio jitter corpus > straggler > matches the checked-in file [0.04ms] moq-doc:check | (pass) audio jitter corpus > straggler > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > straggler > arrives in a monotonic order [0.17ms] moq-doc:check | (pass) audio jitter corpus > straggler > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > straggler > reports every target as a change moq-doc:check | (pass) audio jitter corpus > fixed > matches the checked-in file [0.02ms] moq-doc:check | (pass) audio jitter corpus > fixed > is a trace of equal-length clocks moq-doc:check | (pass) audio jitter corpus > fixed > arrives in a monotonic order [0.09ms] moq-doc:check | (pass) audio jitter corpus > fixed > names a target for the first frame moq-doc:check | (pass) audio jitter corpus > fixed > reports every target as a change moq-doc:check | moq-doc:check | 130 pass moq-doc:check | 0 fail moq-doc:check | 15955 expect() calls moq-doc:check | Ran 130 tests across 3 files. [5.08s] moq-doc:check | API reference: 17 packages in 59.0s moq-doc:check | moq-doc:check | �[32m�[1mvitepress�[22m v1.6.4�[39m moq-doc:check | moq-doc:check | - building client + server bundles... moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m �[1mvitepress-plugin-llms�[22m initialized �[2m(client build)�[22m with workDir: �[36m/work/doc�[39m moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m Build started, file collection cleared moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m Processing �[1m123�[22m markdown files from �[36m/work/doc�[39m moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m Generating �[36mllms.txt�[39m... moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m Generating full documentation bundle (�[36mllms-full.txt�[39m)... moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed concept/audio-jitter.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed lib/c.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed draft/moq-flate.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed bin/demo.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed lib/rs/hang.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed concept/use-case/ai.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed bin/relay/http.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed lib/js/api.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Generated �[36mllms.txt�[39m (~�[1m4.6K�[22m tokens, �[1m14.2 kB�[22m) with �[1m123�[22m documentation links moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed setup/agent.md moq-doc:check | �[34mllmstxt�[39m�[2m » �[22m�[32m✓�[39m Processed bin.md moq-doc:chequest: fixer agent exited 101 (written by Codex) |
|
quest land removed this pull request from the queue: the batch check failed (exit 1). Checking rcgen v0.14.10
Checking ashpd v0.13.13
Compiling proc-macro2-diagnostics v0.10.1
Checking http-cache v1.0.0-alpha.8
Checking moq-sock v0.2.0 (/work/rs/moq-sock)
Checking fs-err v3.3.1
Checking p256 v0.14.0
Checking p384 v0.14.0
Checking arboard v3.7.0
Checking reqwest-middleware v0.5.2
Checking web-transport-trait v0.5.2
Checking egui-winit v0.36.2
Checking prometheus-client v0.25.1
Checking axum v0.8.9
Checking axum-server v0.8.0
Checking egui-wgpu v0.36.2
Checking http-cache-reqwest v1.0.0-alpha.9
Checking moq-auth v0.2.1 (/work/rs/moq-auth)
Compiling duplicate v2.0.1
Checking moq-stats v0.2.12 (/work/rs/moq-stats)
Checking eframe v0.36.2
Checking egui_dock v0.21.1
Checking moq-tokio v0.19.23 (/work/rs/moq-tokio)
Checking moq-relay v0.17.2 (/work/rs/moq-relay)
Checking pipewire v0.10.1
Checking cpal v0.18.2
Checking moq-audio v0.1.10 (/work/rs/moq-audio)
Checking moq-scene v0.1.0 (/work/rs/moq-scene)
Checking moq-studio v0.1.0 (/work/rs/moq-studio)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 16.87s
info: running `cargo clippy --locked --tests --all-features -- -D warnings` on moq-wasm (51/52)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.32s
info: running `cargo clippy --locked --tests --all-features -- -D warnings` on uniffi-bindgen (52/52)
Compiling getrandom v0.4.3
Compiling winnow v1.0.4
Compiling uniffi_internal_macros v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling serde v1.0.229
Compiling libc v0.2.191
Checking indexmap v2.14.2
Compiling fs-err v3.3.1
Compiling askama_parser v0.16.1
Compiling basic-toml v0.1.10
Checking nom v7.1.3
Compiling scroll_derive v0.12.1
Checking smawk v0.3.3
Compiling askama_derive v0.16.1
Checking tempfile v3.27.0
Checking serde_json v1.0.154
Checking weedle2 v5.0.0 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking textwrap v0.16.4
Compiling toml_parser v1.1.3+spec-1.1.0
Checking uniffi_pipeline v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking scroll v0.12.0
Compiling toml_datetime v1.1.1+spec-1.1.0
Checking uniffi_meta v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling askama_macros v0.16.1
Checking plain v0.2.3
Checking clap_builder v4.6.7
Checking cargo_metadata v0.23.1
Compiling toml v1.1.6+spec-1.1.0
Checking uniffi_udl v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking goblin v0.8.2
Checking askama v0.16.1
Checking clap v4.6.7
Checking uniffi_core v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking uniffi_bindgen v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Compiling uniffi_macros v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking uniffi v0.32.2 (https://github.com/kixelated/uniffi-rs?rev=88d835d#88d835d6)
Checking uniffi-bindgen v0.1.0 (/work/rs/uniffi-bindgen)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.74s
mbx[cache]: object cache: 1328 hits, 58 misses, 40 not looked up; 0 B downloaded, 0 B uploaded, 192.7 KiB stored locally
mbx[cache]: 2m 41s session; 27m 41s estimated compiler time avoided (summed across compilations)
mbx[cache]: 40 compilations had no usable prior inputs or matching prediction for a lookup
mbx[cache]: Cargo artifact reuse and CI cache archive transfers are not included above
mbx[savings]: every checkout believes it owns 2.5 TiB of outputs. the disk keeps one copy and says nothing.
ci: check quest failed
ci: seconds per module
310 check rs
159 test rs
326 check rs_shapes
170 check obs_compile
498 check js
80 test js
15 check markdown
3 check gh
73 test gh
218 check flake
0 check drill
10 check quest (failed)
4 check obs
12 check ts_paths
48 check shell
1 check large_files
1 check toml
0 check nix
0 check justfile
796 wall time
error: recipe `ci` failed on line 106 with exit code 1
. |
|
codex / Codex land fixer: (written by codex / Codex) |
|
quest land removed this pull request from the queue: Conflicts with the base: js/net/src/lite/track_stream.test.ts, js/net/src/util/deadline.ts |
|
codex / Codex land fixer: (written by codex / Codex) |
|
quest land removed this pull request from the queue: Conflicts with the base: js/net/src/lite/track_stream.test.ts, js/net/src/util/deadline.ts |
Finishes
quest/m2/js-request-streamand deletes it.What changed
Deadlinereset the raw stream at its deadline, behind theRequestStreamthat owns it, so a timed-out request was ended twice: once by the deadline, then again by the caller's cleanup.Deadline.opennow takes an optional owner wrapper and resets that owner instead. The newRequestStream.open(session, deadline, quic)uses it, so a deadline failure goes throughRequestStream.abortlike abandonment and errors do, and any laterabort/closeis a no-op. SUBSCRIBE, SUBSCRIBE_NAMESPACE, and PUBLISH_NAMESPACE all open this way. Lite keeps usingDeadlineon raw streams; nothing changes there.#cancelSubscribe) went away when moq-dev/moq#6753 dropped drafts 14-17 and that path with them. What it left behind were thesent/tornguards and theafterSetupsplit, which only kept a cleanup from tearing down a stream it still had to write UNSUBSCRIBE on. On 18+ the withdrawal is ending the stream, so the cleanup is now a single idempotent function thatRequestStreammakes safe to run twice.Public API: none (
Deadline,RequestStreamare@internal). Wire: a TRACK with trailing bytes now ends the session instead of the stream.Choices made without asking
js/net/src/lite/publisher.tsrunTrackInfo). I fixed it there.Deadlineobject (lite shares it).RequestStreamowns it by being the thing the deadline resets, not by holding it. Moving the deadline itself intoRequestStreamwould split it from lite for no behavior gain.Checks
request_stream.test.ts:a request's deadline ends it through the request, so later ends do nothing(2 stream aborts before, 1 after).lite/track_stream.test.ts:data after a TRACK request closes the session(drafts 05-07).bun testinjs/net: 2652 pass.just check origin/main: pass.just test interop: all checks passed.quest check: pass.Review
mechanical fix by codex / Codex:
Merged base and mechanically combined test imports and deadline ownership with concurrent-open counting; tests blocked by missing workspace dependencies.(head e690f57)quest review --base origin/main, round 1).10eba9335dd05255a390e79d64ce2d44629949a4.Follow-ups
(Written by Opus 5.5)
🤖 Generated with Claude Code