Skip to main content

moqtap_codec/draft16/
error_codes.rs

1//! Error and status code registries defined by MoQT draft-16.
2//!
3//! Each registry in Section 13.4 of the draft becomes one enum here. Variant names are
4//! the draft's ALLCAPS names in UpperCamelCase; every variant's doc comment repeats the
5//! draft spelling so the mapping stays checkable against the specification.
6//!
7//! `from_u64` returns `None` for a code this draft does not define. Peers legitimately
8//! send codes from other draft versions or from private extensions, so an unknown code
9//! is a decode result to handle, not a fault.
10
11/// Session termination error codes.
12///
13/// Sent in the session-level close. Assigned in Section 13.4.1 of draft-16; the code definitions
14/// are in Section 3.4.
15///
16/// Draft-16 assigns 0x0 through 0x9 and 0x10 through 0x1A. The gap at 0xA through 0xF is the
17/// draft's own; this registry reserves no greasing range.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[repr(u64)]
20pub enum SessionErrorCode {
21    /// `NO_ERROR` — The session is being terminated without an error.
22    NoError = 0x0,
23    /// `INTERNAL_ERROR` — An implementation specific error occurred.
24    InternalError = 0x1,
25    /// `UNAUTHORIZED` — The client is not authorized to establish a session.
26    Unauthorized = 0x2,
27    /// `PROTOCOL_VIOLATION` — The remote endpoint performed an action that was disallowed by the
28    /// specification.
29    ProtocolViolation = 0x3,
30    /// `INVALID_REQUEST_ID` — The session was closed because the endpoint used a Request ID that
31    /// was smaller than or equal to a previously received request ID, or the least-significant bit
32    /// of the request ID was incorrect for the endpoint.
33    InvalidRequestId = 0x4,
34    /// `DUPLICATE_TRACK_ALIAS` — The endpoint attempted to use a Track Alias that was already in
35    /// use.
36    DuplicateTrackAlias = 0x5,
37    /// `KEY_VALUE_FORMATTING_ERROR` — The key-value pair has a formatting error.
38    KeyValueFormattingError = 0x6,
39    /// `TOO_MANY_REQUESTS` — The session was closed because the endpoint used a Request ID equal to
40    /// or larger than the current Maximum Request ID.
41    TooManyRequests = 0x7,
42    /// `INVALID_PATH` — The PATH parameter was used by a server, on a WebTransport session, or the
43    /// server does not support the path.
44    InvalidPath = 0x8,
45    /// `MALFORMED_PATH` — The PATH parameter does not conform to the rules in Section 9.3.1.2.
46    MalformedPath = 0x9,
47    /// `GOAWAY_TIMEOUT` — The session was closed because the peer took too long to close the
48    /// session in response to a GOAWAY (Section 9.4) message. See session migration (Section 3.5).
49    GoawayTimeout = 0x10,
50    /// `CONTROL_MESSAGE_TIMEOUT` — The session was closed because the peer took too long to respond
51    /// to a control message.
52    ControlMessageTimeout = 0x11,
53    /// `DATA_STREAM_TIMEOUT` — The session was closed because the peer took too long to send data
54    /// expected on an open Data Stream (see Section 10). This includes fields of a stream header or
55    /// an object header within a data stream. If an endpoint times out waiting for a new object
56    /// header on an open subgroup stream, it MAY send a STOP_SENDING on that stream or terminate
57    /// the subscription.
58    DataStreamTimeout = 0x12,
59    /// `AUTH_TOKEN_CACHE_OVERFLOW` — The Session limit Section 9.3.1.4 of the size of all
60    /// registered Authorization tokens has been exceeded.
61    AuthTokenCacheOverflow = 0x13,
62    /// `DUPLICATE_AUTH_TOKEN_ALIAS` — Authorization Token attempted to register an Alias that was
63    /// in use (see Section 9.2.2.1).
64    DuplicateAuthTokenAlias = 0x14,
65    /// `VERSION_NEGOTIATION_FAILED` — The client didn't offer a version supported by the server.
66    VersionNegotiationFailed = 0x15,
67    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during registration (see Section
68    /// 9.2.2.1).
69    MalformedAuthToken = 0x16,
70    /// `UNKNOWN_AUTH_TOKEN_ALIAS` — No registered token found for the provided Alias (see Section
71    /// 9.2.2.1).
72    UnknownAuthTokenAlias = 0x17,
73    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 9.2.2.1).
74    ExpiredAuthToken = 0x18,
75    /// `INVALID_AUTHORITY` — The specified AUTHORITY does not correspond to this server or cannot
76    /// be used in this context.
77    InvalidAuthority = 0x19,
78    /// `MALFORMED_AUTHORITY` — The AUTHORITY value is syntactically invalid.
79    MalformedAuthority = 0x1A,
80}
81
82/// Error codes carried in the REQUEST_ERROR control message.
83///
84/// REQUEST_ERROR answers any request (SUBSCRIBE, FETCH, PUBLISH, SUBSCRIBE_NAMESPACE,
85/// PUBLISH_NAMESPACE, TRACK_STATUS). Most codes mean the same thing for every request type, but a
86/// few are request-specific. Assigned in Section 13.4.2 of draft-16; the code definitions are in
87/// Section 9.8.
88///
89/// PUBLISH_NAMESPACE_CANCEL carries a code from this registry as well: Section 9.24 states it uses
90/// the same error codes as the REQUEST_ERROR that responds to PUBLISH_NAMESPACE.
91///
92/// Draft-16 assigns 0x0 through 0x5, 0x10 through 0x12, 0x19, 0x20, 0x30 and 0x32. The registry is
93/// sparse by design and reserves no greasing range.
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95#[repr(u64)]
96pub enum RequestErrorCode {
97    /// `INTERNAL_ERROR` — An implementation specific or generic error occurred.
98    InternalError = 0x0,
99    /// `UNAUTHORIZED` — The subscriber is not authorized to perform the requested action on the
100    /// given track. This might be retryable if the authorization token is not yet valid.
101    Unauthorized = 0x1,
102    /// `TIMEOUT` — The subscription could not be completed before an implementation specific
103    /// timeout. For example, a relay could not establish an upstream subscription within the
104    /// timeout.
105    Timeout = 0x2,
106    /// `NOT_SUPPORTED` — The endpoint does not support the type of request.
107    NotSupported = 0x3,
108    /// `MALFORMED_AUTH_TOKEN` — Invalid Auth Token serialization during registration (see Section
109    /// 9.2.2.1).
110    MalformedAuthToken = 0x4,
111    /// `EXPIRED_AUTH_TOKEN` — Authorization token has expired (Section 9.2.2.1).
112    ExpiredAuthToken = 0x5,
113    /// `DOES_NOT_EXIST` — The track or namespace is not available at the publisher.
114    DoesNotExist = 0x10,
115    /// `INVALID_RANGE` — In response to SUBSCRIBE or FETCH, specified Filter or range of Locations
116    /// cannot be satisfied.
117    InvalidRange = 0x11,
118    /// `MALFORMED_TRACK` — In response to a FETCH, a relay publisher detected the track was
119    /// malformed (see Section 2.4.2).
120    MalformedTrack = 0x12,
121    /// `DUPLICATE_SUBSCRIPTION` — The PUBLISH or SUBSCRIBE request attempted to create a
122    /// subscription to a Track with the same role as an existing subscription.
123    DuplicateSubscription = 0x19,
124    /// `UNINTERESTED` — The subscriber is not interested in the track or namespace.
125    Uninterested = 0x20,
126    /// `PREFIX_OVERLAP` — In response to SUBSCRIBE_NAMESPACE, the namespace prefix overlaps with
127    /// another SUBSCRIBE_NAMESPACE in the same session.
128    PrefixOverlap = 0x30,
129    /// `INVALID_JOINING_REQUEST_ID` — In response to a Joining FETCH, the referenced Request ID is
130    /// not an Established Subscription.
131    InvalidJoiningRequestId = 0x32,
132}
133
134/// Status codes carried in the PUBLISH_DONE control message.
135///
136/// Indicates why a subscription ended, and whether ending it was an error. Assigned in Section
137/// 13.4.3 of draft-16; the code definitions are in Section 9.15.
138///
139/// Draft-16 assigns 0x0 through 0x6, 0x8 and 0x12. The hole at 0x7 is real and deliberate:
140/// draft-15 assigned 0x7 to MALFORMED_TRACK, and draft-16 moved that code to 0x12 without
141/// reassigning 0x7. Section 9.15 also lists MALFORMED_TRACK ahead of UPDATE_FAILED in its prose
142/// while the registry table lists both in numeric order; the two agree on names and values.
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144#[repr(u64)]
145pub enum PublishDoneStatusCode {
146    /// `INTERNAL_ERROR` — An implementation specific or generic error occurred.
147    InternalError = 0x0,
148    /// `UNAUTHORIZED` — The subscriber is no longer authorized to subscribe to the given track.
149    Unauthorized = 0x1,
150    /// `TRACK_ENDED` — The track is no longer being published.
151    TrackEnded = 0x2,
152    /// `SUBSCRIPTION_ENDED` — The publisher reached the end of an associated subscription filter.
153    SubscriptionEnded = 0x3,
154    /// `GOING_AWAY` — The subscriber or publisher issued a GOAWAY message.
155    GoingAway = 0x4,
156    /// `EXPIRED` — The publisher reached the timeout specified in SUBSCRIBE_OK.
157    Expired = 0x5,
158    /// `TOO_FAR_BEHIND` — The publisher's queue of objects to be sent to the given subscriber
159    /// exceeds its implementation defined limit.
160    TooFarBehind = 0x6,
161    /// `UPDATE_FAILED` — REQUEST_UPDATE failed on this subscription (see Section 9.11).
162    UpdateFailed = 0x8,
163    /// `MALFORMED_TRACK` — A relay publisher detected that the track was malformed (see Section
164    /// 2.4.2).
165    MalformedTrack = 0x12,
166}
167
168/// Error codes carried in RESET_STREAM and RESET_STREAM_AT on a data stream.
169///
170/// Sent when a publisher closes a subgroup or fetch stream before delivering every object on it.
171/// Assigned in Section 13.4.4 of draft-16; the code definitions are in Section 10.4.3. These are
172/// application error codes carried on the stream, not session-level codes.
173///
174/// Draft-16 assigns 0x0 through 0x4 and 0x12, and reserves no greasing range.
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176#[repr(u64)]
177pub enum DataStreamResetErrorCode {
178    /// `INTERNAL_ERROR` — An implementation specific error.
179    InternalError = 0x0,
180    /// `CANCELLED` — The subscriber requested cancellation via UNSUBSCRIBE, FETCH_CANCEL or
181    /// STOP_SENDING, or the publisher ended the subscription, in which case PUBLISH_DONE (Section
182    /// 9.15) will have a more detailed status code.
183    Cancelled = 0x1,
184    /// `DELIVERY_TIMEOUT` — The DELIVERY TIMEOUT Section 9.2.2.2 was exceeded for this stream.
185    DeliveryTimeout = 0x2,
186    /// `SESSION_CLOSED` — The publisher session is being closed.
187    SessionClosed = 0x3,
188    /// `UNKNOWN_OBJECT_STATUS` — In response to a FETCH, the publisher is unable to determine the
189    /// Status of the next Object in the requested range.
190    UnknownObjectStatus = 0x4,
191    /// `MALFORMED_TRACK` — A relay publisher detected that the track was malformed (see Section
192    /// 2.4.2).
193    MalformedTrack = 0x12,
194}
195
196impl SessionErrorCode {
197    /// Every session termination code draft-16 assigns, in ascending wire order.
198    ///
199    /// This is the set [`Self::from_u64`] accepts, written out so that it can
200    /// be enumerated: nothing can iterate an enum's variants, so a caller that
201    /// wants the registry has to be handed it. Writing it down is also what
202    /// lets a test state its claims about the registry itself rather than about
203    /// the range some sweep happens to reach.
204    pub const ALL: &[SessionErrorCode] = &[
205        SessionErrorCode::NoError,
206        SessionErrorCode::InternalError,
207        SessionErrorCode::Unauthorized,
208        SessionErrorCode::ProtocolViolation,
209        SessionErrorCode::InvalidRequestId,
210        SessionErrorCode::DuplicateTrackAlias,
211        SessionErrorCode::KeyValueFormattingError,
212        SessionErrorCode::TooManyRequests,
213        SessionErrorCode::InvalidPath,
214        SessionErrorCode::MalformedPath,
215        SessionErrorCode::GoawayTimeout,
216        SessionErrorCode::ControlMessageTimeout,
217        SessionErrorCode::DataStreamTimeout,
218        SessionErrorCode::AuthTokenCacheOverflow,
219        SessionErrorCode::DuplicateAuthTokenAlias,
220        SessionErrorCode::VersionNegotiationFailed,
221        SessionErrorCode::MalformedAuthToken,
222        SessionErrorCode::UnknownAuthTokenAlias,
223        SessionErrorCode::ExpiredAuthToken,
224        SessionErrorCode::InvalidAuthority,
225        SessionErrorCode::MalformedAuthority,
226    ];
227
228    /// Convert a raw u64 to a `SessionErrorCode`, if this draft defines that code.
229    pub fn from_u64(v: u64) -> Option<Self> {
230        match v {
231            0x0 => Some(SessionErrorCode::NoError),
232            0x1 => Some(SessionErrorCode::InternalError),
233            0x2 => Some(SessionErrorCode::Unauthorized),
234            0x3 => Some(SessionErrorCode::ProtocolViolation),
235            0x4 => Some(SessionErrorCode::InvalidRequestId),
236            0x5 => Some(SessionErrorCode::DuplicateTrackAlias),
237            0x6 => Some(SessionErrorCode::KeyValueFormattingError),
238            0x7 => Some(SessionErrorCode::TooManyRequests),
239            0x8 => Some(SessionErrorCode::InvalidPath),
240            0x9 => Some(SessionErrorCode::MalformedPath),
241            0x10 => Some(SessionErrorCode::GoawayTimeout),
242            0x11 => Some(SessionErrorCode::ControlMessageTimeout),
243            0x12 => Some(SessionErrorCode::DataStreamTimeout),
244            0x13 => Some(SessionErrorCode::AuthTokenCacheOverflow),
245            0x14 => Some(SessionErrorCode::DuplicateAuthTokenAlias),
246            0x15 => Some(SessionErrorCode::VersionNegotiationFailed),
247            0x16 => Some(SessionErrorCode::MalformedAuthToken),
248            0x17 => Some(SessionErrorCode::UnknownAuthTokenAlias),
249            0x18 => Some(SessionErrorCode::ExpiredAuthToken),
250            0x19 => Some(SessionErrorCode::InvalidAuthority),
251            0x1A => Some(SessionErrorCode::MalformedAuthority),
252            _ => None,
253        }
254    }
255
256    /// Return the raw u64 value of this error code.
257    pub fn as_u64(self) -> u64 {
258        self as u64
259    }
260}
261
262impl RequestErrorCode {
263    /// Every REQUEST_ERROR code draft-16 assigns, in ascending wire order.
264    ///
265    /// This is the set [`Self::from_u64`] accepts, written out so that it can
266    /// be enumerated: nothing can iterate an enum's variants, so a caller that
267    /// wants the registry has to be handed it. Writing it down is also what
268    /// lets a test state its claims about the registry itself rather than about
269    /// the range some sweep happens to reach.
270    pub const ALL: &[RequestErrorCode] = &[
271        RequestErrorCode::InternalError,
272        RequestErrorCode::Unauthorized,
273        RequestErrorCode::Timeout,
274        RequestErrorCode::NotSupported,
275        RequestErrorCode::MalformedAuthToken,
276        RequestErrorCode::ExpiredAuthToken,
277        RequestErrorCode::DoesNotExist,
278        RequestErrorCode::InvalidRange,
279        RequestErrorCode::MalformedTrack,
280        RequestErrorCode::DuplicateSubscription,
281        RequestErrorCode::Uninterested,
282        RequestErrorCode::PrefixOverlap,
283        RequestErrorCode::InvalidJoiningRequestId,
284    ];
285
286    /// Convert a raw u64 to a `RequestErrorCode`, if this draft defines that code.
287    pub fn from_u64(v: u64) -> Option<Self> {
288        match v {
289            0x0 => Some(RequestErrorCode::InternalError),
290            0x1 => Some(RequestErrorCode::Unauthorized),
291            0x2 => Some(RequestErrorCode::Timeout),
292            0x3 => Some(RequestErrorCode::NotSupported),
293            0x4 => Some(RequestErrorCode::MalformedAuthToken),
294            0x5 => Some(RequestErrorCode::ExpiredAuthToken),
295            0x10 => Some(RequestErrorCode::DoesNotExist),
296            0x11 => Some(RequestErrorCode::InvalidRange),
297            0x12 => Some(RequestErrorCode::MalformedTrack),
298            0x19 => Some(RequestErrorCode::DuplicateSubscription),
299            0x20 => Some(RequestErrorCode::Uninterested),
300            0x30 => Some(RequestErrorCode::PrefixOverlap),
301            0x32 => Some(RequestErrorCode::InvalidJoiningRequestId),
302            _ => None,
303        }
304    }
305
306    /// Return the raw u64 value of this error code.
307    pub fn as_u64(self) -> u64 {
308        self as u64
309    }
310}
311
312impl PublishDoneStatusCode {
313    /// Every PUBLISH_DONE status code draft-16 assigns, in ascending wire order.
314    ///
315    /// This is the set [`Self::from_u64`] accepts, written out so that it can
316    /// be enumerated: nothing can iterate an enum's variants, so a caller that
317    /// wants the registry has to be handed it. Writing it down is also what
318    /// lets a test state its claims about the registry itself rather than about
319    /// the range some sweep happens to reach.
320    pub const ALL: &[PublishDoneStatusCode] = &[
321        PublishDoneStatusCode::InternalError,
322        PublishDoneStatusCode::Unauthorized,
323        PublishDoneStatusCode::TrackEnded,
324        PublishDoneStatusCode::SubscriptionEnded,
325        PublishDoneStatusCode::GoingAway,
326        PublishDoneStatusCode::Expired,
327        PublishDoneStatusCode::TooFarBehind,
328        PublishDoneStatusCode::UpdateFailed,
329        PublishDoneStatusCode::MalformedTrack,
330    ];
331
332    /// Convert a raw u64 to a `PublishDoneStatusCode`, if this draft defines that code.
333    pub fn from_u64(v: u64) -> Option<Self> {
334        match v {
335            0x0 => Some(PublishDoneStatusCode::InternalError),
336            0x1 => Some(PublishDoneStatusCode::Unauthorized),
337            0x2 => Some(PublishDoneStatusCode::TrackEnded),
338            0x3 => Some(PublishDoneStatusCode::SubscriptionEnded),
339            0x4 => Some(PublishDoneStatusCode::GoingAway),
340            0x5 => Some(PublishDoneStatusCode::Expired),
341            0x6 => Some(PublishDoneStatusCode::TooFarBehind),
342            0x8 => Some(PublishDoneStatusCode::UpdateFailed),
343            0x12 => Some(PublishDoneStatusCode::MalformedTrack),
344            _ => None,
345        }
346    }
347
348    /// Return the raw u64 value of this status code.
349    pub fn as_u64(self) -> u64 {
350        self as u64
351    }
352}
353
354impl DataStreamResetErrorCode {
355    /// Every data stream reset code draft-16 assigns, in ascending wire order.
356    ///
357    /// This is the set [`Self::from_u64`] accepts, written out so that it can
358    /// be enumerated: nothing can iterate an enum's variants, so a caller that
359    /// wants the registry has to be handed it. Writing it down is also what
360    /// lets a test state its claims about the registry itself rather than about
361    /// the range some sweep happens to reach.
362    pub const ALL: &[DataStreamResetErrorCode] = &[
363        DataStreamResetErrorCode::InternalError,
364        DataStreamResetErrorCode::Cancelled,
365        DataStreamResetErrorCode::DeliveryTimeout,
366        DataStreamResetErrorCode::SessionClosed,
367        DataStreamResetErrorCode::UnknownObjectStatus,
368        DataStreamResetErrorCode::MalformedTrack,
369    ];
370
371    /// Convert a raw u64 to a `DataStreamResetErrorCode`, if this draft defines that code.
372    pub fn from_u64(v: u64) -> Option<Self> {
373        match v {
374            0x0 => Some(DataStreamResetErrorCode::InternalError),
375            0x1 => Some(DataStreamResetErrorCode::Cancelled),
376            0x2 => Some(DataStreamResetErrorCode::DeliveryTimeout),
377            0x3 => Some(DataStreamResetErrorCode::SessionClosed),
378            0x4 => Some(DataStreamResetErrorCode::UnknownObjectStatus),
379            0x12 => Some(DataStreamResetErrorCode::MalformedTrack),
380            _ => None,
381        }
382    }
383
384    /// Return the raw u64 value of this error code.
385    pub fn as_u64(self) -> u64 {
386        self as u64
387    }
388}