Skip to content

moq-native,relay: don't advertise the illegal qmux-00.moqt-18 pair#1579

Merged
kixelated merged 2 commits into
devfrom
claude/qmux-pin-draft18
Jun 1, 2026
Merged

moq-native,relay: don't advertise the illegal qmux-00.moqt-18 pair#1579
kixelated merged 2 commits into
devfrom
claude/qmux-pin-draft18

Conversation

@kixelated
Copy link
Copy Markdown
Collaborator

@kixelated kixelated commented Jun 1, 2026

Summary

moq-transport-18 requires qmux-01, so qmux-00.moqt-18 is an illegal WebSocket subprotocol pair. On dev the Rust side advertised the full {qmux-01, qmux-00} × moq_net::ALPNS matrix (relay) and offered every draft per ALPN (&[], native client/listener), which produces that illegal pair. js/net's connect.ts already pins draft-18 to qmux-01, so the Rust side was the outlier; this brings it in line.

  • rs/moq-native/src/websocket.rs: add a private qmux_versions_for(alpn) helper that pins moqt-18 to qmux-01 and returns &[] (every draft) for all other ALPNs. Used by both the WebSocket client connect() and the WebSocketListener.
  • rs/moq-relay/src/websocket.rs: supported_subprotocols() skips the qmux-00.moqt-18 cell of the matrix.
  • Each crate guards the "moqt-18" literal with a test asserting it stays the IETF draft-18 ALPN (wire 0xff000012), so the pin can't silently rot.

No new public API. js/net already encodes this policy, so no JS change is needed.

Background

This supersedes #1513, which added a moq-net version→qmux policy mapping (QmuxVersion, qmux_versions(), QMUX_ALPNS, QMUX_ALPN_STRINGS, etc.) as a workaround for qmux 0.1.0. dev's qmux 0.1.1 with_protocols(alpn, &[Version]) API plus the full-matrix supported_subprotocols() already handle qmux negotiation, so that surface is redundant. The only real gap was the one illegal pair, which this fixes minimally.

Test plan

  • cargo test -p moq-native -p moq-relay --lib websocket:: — passes, including:
    • moqt_18_pins_to_qmux01 / supported_subprotocols_lists_full_matrix: the pin and the advertised matrix (with the illegal pair excluded), plus draft-18 literal drift guards.
    • every_advertised_pair_is_acceptable: spins up the axum WebSocket handler and, for every versioned (qmux, moq) pair we advertise, connects a client offering exactly that pair and asserts it negotiates end-to-end; also asserts offering qmux-00.moqt-18 fails the handshake.
    • axum_ws_negotiates_newest_moq_alpn: existing newest-ALPN regression, refactored onto a shared spawn_test_server harness.
  • cargo fmt -p moq-native -p moq-relay -- --check clean.
  • cargo clippy -p moq-native -p moq-relay --all-targets -- -D warnings clean.

(Written by Claude)

moq-transport-18 requires qmux-01, so `qmux-00.moqt-18` is an illegal
WebSocket subprotocol pair. dev advertised the full qmux x moq ALPN
matrix (and offered every draft per ALPN), which produced that pair;
js/net already pins draft-18 to qmux-01, so the Rust side was the
outlier.

Add a `qmux_versions_for` helper in moq-native that pins moqt-18 to
qmux-01 and leaves every other ALPN unrestricted (`&[]`, expanded by
qmux), used by both the WebSocket client and listener. The relay's
`supported_subprotocols` skips the qmux-00.moqt-18 cell. Each crate
guards the "moqt-18" literal with a test so it stays the draft-18 ALPN.

No new public API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kixelated kixelated enabled auto-merge (squash) June 1, 2026 19:05
Share the axum test harness behind a `spawn_test_server` helper and add
`every_advertised_pair_is_acceptable`: for each versioned `(qmux, moq)`
pair in `supported_subprotocols`, a client offering exactly that pair must
negotiate it end-to-end. Conversely, offering the excluded `qmux-00.moqt-18`
pair must fail the handshake rather than silently downgrade.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kixelated kixelated merged commit 1234f49 into dev Jun 1, 2026
1 check passed
@kixelated kixelated deleted the claude/qmux-pin-draft18 branch June 1, 2026 19:40
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.

1 participant