Skip to content

fix(webtransport): buffer track objects that arrive before their SUBSCRIBE_OK binds an alias - #1

Open
mimcz wants to merge 1 commit into
openmoq:mainfrom
mimcz:fix/webtransport-pending-alias-buffering
Open

fix(webtransport): buffer track objects that arrive before their SUBSCRIBE_OK binds an alias#1
mimcz wants to merge 1 commit into
openmoq:mainfrom
mimcz:fix/webtransport-pending-alias-buffering

Conversation

@mimcz

@mimcz mimcz commented Aug 4, 2026

Copy link
Copy Markdown

Control and data streams aren't ordered relative to each other (draft-ietf-moq-transport-16 §10.4), so a publisher can deliver a subscription's objects before SUBSCRIBE_OK binds the Track Alias. routeToTrackSubscription dropped these silently - for tracks that are a single object at group 0 (catalogs, init segments), this loses the track permanently and the subscription hangs.

Buffers objects (and graceful subgroup FINs) per-alias while any subscribeTrack() is pending, capped at 256, replayed once SUBSCRIBE_OK binds. Buffers clear once nothing is left pending to claim them. Also adds an onSubgroupClosed callback to TrackSubscribeOptions, needed to buffer a FIN the same way as objects.

Testing: new regression test in adapter.test.ts (confirmed it fails
without the fix); full packages/webtransport suite passes; tsc --noEmit clean; verified live against a real draft-14 relay via a downstream integration.

Originally patched locally against v0.5.0; re-derived here against current adapter.ts.


This change is Reviewable

…CRIBE_OK binds an alias

The control stream (carrying SUBSCRIBE_OK) and unidirectional data
streams (carrying Objects) are not ordered relative to each other
(draft-ietf-moq-transport-16 section 10.4). A publisher can legitimately
deliver a subscription data before the local subscriber has processed
SUBSCRIBE_OK and bound the Track Alias in rawAliasMaps.

routeToTrackSubscription previously returned false for any alias with
no bound route yet, silently dropping the object. For tracks whose
entire content is a single object at group 0 (MSF/CMAF catalogs, init
segments) this loses the track permanently and the subscription hangs
- nondeterministically, depending on relay/publisher timing.

Buffer objects (and graceful subgroup-stream FINs) for an unbound alias
while any subscribeTrack() call is still pending, capped at 256 per
alias, and replay them in submission order once SUBSCRIBE_OK binds the
alias. Buffers are cleared whenever no subscription is left pending to
claim them (REQUEST_ERROR, subscribeTrack() send failure, or session
teardown), so nothing lingers past its possible owner.

Also adds an optional onSubgroupClosed callback to TrackSubscribeOptions
- the only reliable end-of-subgroup signal available when a publisher
does not set the subgroup header END_OF_GROUP flag, needed here so a
graceful FIN racing SUBSCRIBE_OK can be buffered and replayed the same
way as objects.

Found and originally patched locally against v0.5.0 while integrating
this library into a downstream player against a real relay; the race
reproduces reliably enough in practice that it was carried as a
submodule patch. Re-derived here against the current adapter.ts.
@rwl4

rwl4 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR. That race is real and the regression test is useful, but I need some changes before merging: the current fallback can consume objects belonging to established subscribe() calls, replay before the mutable callback contract can be honored, buffer peer-controlled data without global byte/alias/time limits (and silently discard on overflow while still claiming the object), and retain stale data across several terminal paths and alias reuse.

Please rework it so the buffer never claims aliases already bound to other subscriptions and fails closed when limits are hit, with cleanup centralized on every settlement and cancellation path, and replay deferred to where the callback contract holds (the pendingFetchStreams parking + tombstone pattern in adapter.ts is the in-house precedent to follow).

Tests for each of those cases, please. :)

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.

2 participants