Skip to main content

moqtap_codec/draft11/
message.rs

1//! Draft-11 control message encoding and decoding.
2//!
3//! Key changes from draft-09/10:
4//! - Setup IDs: 0x40/0x41 -> 0x20/0x21
5//! - `subscribe_id` -> `request_id` throughout
6//! - MaxSubscribeId -> MaxRequestId, SubscribesBlocked -> RequestsBlocked
7//! - Subscribe gains `track_alias` and `forward` fields
8//! - SubscribeOk: no track_alias
9//! - SubscribeError gains trailing `track_alias`
10//! - SubscribeDone gains `stream_count`
11//! - SubscribeUpdate uses start_group/start_object (not Location)
12//! - Announce gains `request_id`; AnnounceOk/AnnounceError use `request_id`
13//! - AnnounceCancel: `namespace + error_code + reason_phrase`
14//! - SubscribeAnnounces gains `request_id`
15//! - TrackStatusRequest gains `request_id` and `parameters`
16//! - TrackStatus restructured: `request_id + status_code + largest_location + parameters`
17//! - Fetch restructured: 3 fetch types (Standalone, RelativeJoining, AbsoluteJoining)
18//! - FetchOk: group_order + end_of_track + end_location (no track_alias)
19//! - Uses even/odd KVP encoding (not d07 format)
20//! - Framing: type_id(vi) + payload_length(16) + payload
21
22use crate::auth_token::{AuthorizationToken, AUTH_TOKEN_PARAMETER_D11};
23use crate::error::{
24    CodecError, MAX_FULL_TRACK_NAME_LENGTH, MAX_GOAWAY_URI_LENGTH, MAX_MESSAGE_LENGTH,
25    MAX_REASON_PHRASE_LENGTH,
26};
27use crate::kvp::{KeyValuePair, KvpValue};
28use crate::types::{self, *};
29pub use crate::types::{check_group_range, check_location_range, check_open_ended_group_range};
30use crate::varint::VarInt;
31use bytes::{Buf, BufMut};
32
33/// Control message type IDs (draft-11).
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[repr(u64)]
36pub enum MessageType {
37    /// SubscribeUpdate (type 0x02).
38    SubscribeUpdate = 0x02,
39    /// Subscribe (type 0x03).
40    Subscribe = 0x03,
41    /// SubscribeOk (type 0x04).
42    SubscribeOk = 0x04,
43    /// SubscribeError (type 0x05).
44    SubscribeError = 0x05,
45    /// Announce (type 0x06).
46    Announce = 0x06,
47    /// AnnounceOk (type 0x07).
48    AnnounceOk = 0x07,
49    /// AnnounceError (type 0x08).
50    AnnounceError = 0x08,
51    /// Unannounce (type 0x09).
52    Unannounce = 0x09,
53    /// Unsubscribe (type 0x0A).
54    Unsubscribe = 0x0A,
55    /// SubscribeDone (type 0x0B).
56    SubscribeDone = 0x0B,
57    /// AnnounceCancel (type 0x0C).
58    AnnounceCancel = 0x0C,
59    /// TrackStatusRequest (type 0x0D).
60    TrackStatusRequest = 0x0D,
61    /// TrackStatus (type 0x0E).
62    TrackStatus = 0x0E,
63    /// GoAway (type 0x10).
64    GoAway = 0x10,
65    /// SubscribeAnnounces (type 0x11).
66    SubscribeAnnounces = 0x11,
67    /// SubscribeAnnouncesOk (type 0x12).
68    SubscribeAnnouncesOk = 0x12,
69    /// SubscribeAnnouncesError (type 0x13).
70    SubscribeAnnouncesError = 0x13,
71    /// UnsubscribeAnnounces (type 0x14).
72    UnsubscribeAnnounces = 0x14,
73    /// MaxRequestId (type 0x15).
74    MaxRequestId = 0x15,
75    /// Fetch (type 0x16).
76    Fetch = 0x16,
77    /// FetchCancel (type 0x17).
78    FetchCancel = 0x17,
79    /// FetchOk (type 0x18).
80    FetchOk = 0x18,
81    /// FetchError (type 0x19).
82    FetchError = 0x19,
83    /// RequestsBlocked (type 0x1A).
84    RequestsBlocked = 0x1A,
85    /// ClientSetup (type 0x20).
86    ClientSetup = 0x20,
87    /// ServerSetup (type 0x21).
88    ServerSetup = 0x21,
89}
90
91impl MessageType {
92    /// Look up a message type by its wire ID.
93    pub fn from_id(id: u64) -> Option<Self> {
94        match id {
95            0x02 => Some(MessageType::SubscribeUpdate),
96            0x03 => Some(MessageType::Subscribe),
97            0x04 => Some(MessageType::SubscribeOk),
98            0x05 => Some(MessageType::SubscribeError),
99            0x06 => Some(MessageType::Announce),
100            0x07 => Some(MessageType::AnnounceOk),
101            0x08 => Some(MessageType::AnnounceError),
102            0x09 => Some(MessageType::Unannounce),
103            0x0A => Some(MessageType::Unsubscribe),
104            0x0B => Some(MessageType::SubscribeDone),
105            0x0C => Some(MessageType::AnnounceCancel),
106            0x0D => Some(MessageType::TrackStatusRequest),
107            0x0E => Some(MessageType::TrackStatus),
108            0x10 => Some(MessageType::GoAway),
109            0x11 => Some(MessageType::SubscribeAnnounces),
110            0x12 => Some(MessageType::SubscribeAnnouncesOk),
111            0x13 => Some(MessageType::SubscribeAnnouncesError),
112            0x14 => Some(MessageType::UnsubscribeAnnounces),
113            0x15 => Some(MessageType::MaxRequestId),
114            0x16 => Some(MessageType::Fetch),
115            0x17 => Some(MessageType::FetchCancel),
116            0x18 => Some(MessageType::FetchOk),
117            0x19 => Some(MessageType::FetchError),
118            0x1A => Some(MessageType::RequestsBlocked),
119            0x20 => Some(MessageType::ClientSetup),
120            0x21 => Some(MessageType::ServerSetup),
121            _ => None,
122        }
123    }
124
125    /// Return the wire ID for this message type.
126    pub fn id(&self) -> u64 {
127        *self as u64
128    }
129
130    /// This type's name in the shared vector corpus: the `message_type` its
131    /// draft's `codec/messages/*.json` files carry, in `snake_case`.
132    pub fn name(&self) -> &'static str {
133        match self {
134            MessageType::SubscribeUpdate => "subscribe_update",
135            MessageType::Subscribe => "subscribe",
136            MessageType::SubscribeOk => "subscribe_ok",
137            MessageType::SubscribeError => "subscribe_error",
138            MessageType::Announce => "announce",
139            MessageType::AnnounceOk => "announce_ok",
140            MessageType::AnnounceError => "announce_error",
141            MessageType::Unannounce => "unannounce",
142            MessageType::Unsubscribe => "unsubscribe",
143            MessageType::SubscribeDone => "subscribe_done",
144            MessageType::AnnounceCancel => "announce_cancel",
145            MessageType::TrackStatusRequest => "track_status_request",
146            MessageType::TrackStatus => "track_status",
147            MessageType::GoAway => "goaway",
148            MessageType::SubscribeAnnounces => "subscribe_announces",
149            MessageType::SubscribeAnnouncesOk => "subscribe_announces_ok",
150            MessageType::SubscribeAnnouncesError => "subscribe_announces_error",
151            MessageType::UnsubscribeAnnounces => "unsubscribe_announces",
152            MessageType::MaxRequestId => "max_request_id",
153            MessageType::Fetch => "fetch",
154            MessageType::FetchCancel => "fetch_cancel",
155            MessageType::FetchOk => "fetch_ok",
156            MessageType::FetchError => "fetch_error",
157            MessageType::RequestsBlocked => "requests_blocked",
158            MessageType::ClientSetup => "client_setup",
159            MessageType::ServerSetup => "server_setup",
160        }
161    }
162}
163
164// ============================================================
165// Session Lifecycle Messages
166// ============================================================
167
168/// CLIENT_SETUP message (type 0x20).
169#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct ClientSetup {
171    /// List of MoQT versions supported by the client.
172    pub supported_versions: Vec<VarInt>,
173    /// Setup parameters (even/odd KVP encoding).
174    pub parameters: Vec<KeyValuePair>,
175}
176
177/// SERVER_SETUP message (type 0x21).
178#[derive(Debug, Clone, PartialEq, Eq)]
179pub struct ServerSetup {
180    /// The MoQT version selected by the server.
181    pub selected_version: VarInt,
182    /// Setup parameters (even/odd KVP encoding).
183    pub parameters: Vec<KeyValuePair>,
184}
185
186/// GOAWAY message (type 0x10).
187#[derive(Debug, Clone, PartialEq, Eq)]
188pub struct GoAway {
189    /// URI for the new session to connect to.
190    pub new_session_uri: Vec<u8>,
191}
192
193/// MAX_REQUEST_ID message (type 0x15).
194#[derive(Debug, Clone, PartialEq, Eq)]
195pub struct MaxRequestId {
196    /// The maximum request ID the peer may use.
197    pub request_id: VarInt,
198}
199
200/// REQUESTS_BLOCKED message (type 0x1A).
201#[derive(Debug, Clone, PartialEq, Eq)]
202pub struct RequestsBlocked {
203    /// The request ID that is currently blocked on.
204    pub maximum_request_id: VarInt,
205}
206
207// ============================================================
208// Subscribe Messages
209// ============================================================
210
211/// SUBSCRIBE message (type 0x03).
212#[derive(Debug, Clone, PartialEq, Eq)]
213pub struct Subscribe {
214    /// The request ID for this subscription.
215    pub request_id: VarInt,
216    /// The track alias assigned by the subscriber.
217    pub track_alias: VarInt,
218    /// The track namespace.
219    pub track_namespace: TrackNamespace,
220    /// The track name within the namespace.
221    pub track_name: Vec<u8>,
222    /// Subscriber priority for this track.
223    pub subscriber_priority: u8,
224    /// Requested group delivery order.
225    pub group_order: GroupOrder,
226    /// Whether to forward data on this subscription.
227    pub forward: Forward,
228    /// The filter type controlling which objects are delivered.
229    pub filter_type: VarInt,
230    /// Present only for AbsoluteStart (3) and AbsoluteRange (4) filter types.
231    pub start_group: Option<VarInt>,
232    /// Present only for AbsoluteStart (3) and AbsoluteRange (4) filter types.
233    pub start_object: Option<VarInt>,
234    /// Present only for AbsoluteRange (4) filter type.
235    pub end_group: Option<VarInt>,
236    /// Subscribe parameters (even/odd KVP encoding).
237    pub parameters: Vec<KeyValuePair>,
238}
239
240/// SUBSCRIBE_OK message (type 0x04).
241#[derive(Debug, Clone, PartialEq, Eq)]
242pub struct SubscribeOk {
243    /// The request ID this response corresponds to.
244    pub request_id: VarInt,
245    /// Subscription expiry in milliseconds (0 = no expiry).
246    pub expires: VarInt,
247    /// The group delivery order chosen by the publisher.
248    pub group_order: GroupOrder,
249    /// Whether the largest location is included.
250    pub content_exists: ContentExists,
251    /// Present only when content_exists says one is there.
252    pub largest_location: Option<Location>,
253    /// Response parameters (even/odd KVP encoding).
254    pub parameters: Vec<KeyValuePair>,
255}
256
257/// SUBSCRIBE_ERROR message (type 0x05).
258#[derive(Debug, Clone, PartialEq, Eq)]
259pub struct SubscribeError {
260    /// The request ID this error corresponds to.
261    pub request_id: VarInt,
262    /// Application-defined error code.
263    pub error_code: VarInt,
264    /// Human-readable reason phrase.
265    pub reason_phrase: Vec<u8>,
266    /// The track alias.
267    pub track_alias: VarInt,
268}
269
270/// SUBSCRIBE_UPDATE message (type 0x02).
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub struct SubscribeUpdate {
273    /// The request ID of the subscription to update.
274    pub request_id: VarInt,
275    /// Updated start group.
276    pub start_group: VarInt,
277    /// Updated start object.
278    pub start_object: VarInt,
279    /// Updated end group (0 = open-ended).
280    pub end_group: VarInt,
281    /// Updated subscriber priority.
282    pub subscriber_priority: u8,
283    /// Updated forward preference.
284    pub forward: Forward,
285    /// Updated parameters (even/odd KVP encoding).
286    pub parameters: Vec<KeyValuePair>,
287}
288
289/// SUBSCRIBE_DONE message (type 0x0B).
290#[derive(Debug, Clone, PartialEq, Eq)]
291pub struct SubscribeDone {
292    /// The request ID of the completed subscription.
293    pub request_id: VarInt,
294    /// Status code indicating the reason for completion.
295    pub status_code: VarInt,
296    /// The number of streams opened for this subscription.
297    pub stream_count: VarInt,
298    /// Human-readable reason phrase.
299    pub reason_phrase: Vec<u8>,
300}
301
302/// UNSUBSCRIBE message (type 0x0A).
303#[derive(Debug, Clone, PartialEq, Eq)]
304pub struct Unsubscribe {
305    /// The request ID of the subscription to cancel.
306    pub request_id: VarInt,
307}
308
309// ============================================================
310// Announce Messages
311// ============================================================
312
313/// ANNOUNCE message (type 0x06).
314#[derive(Debug, Clone, PartialEq, Eq)]
315pub struct Announce {
316    /// The request ID for this announcement.
317    pub request_id: VarInt,
318    /// The track namespace to announce.
319    pub track_namespace: TrackNamespace,
320    /// Announce parameters (even/odd KVP encoding).
321    pub parameters: Vec<KeyValuePair>,
322}
323
324/// ANNOUNCE_OK message (type 0x07).
325#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct AnnounceOk {
327    /// The request ID this response corresponds to.
328    pub request_id: VarInt,
329}
330
331/// ANNOUNCE_ERROR message (type 0x08).
332#[derive(Debug, Clone, PartialEq, Eq)]
333pub struct AnnounceError {
334    /// The request ID this error corresponds to.
335    pub request_id: VarInt,
336    /// Application-defined error code.
337    pub error_code: VarInt,
338    /// Human-readable reason phrase.
339    pub reason_phrase: Vec<u8>,
340}
341
342/// ANNOUNCE_CANCEL message (type 0x0C).
343#[derive(Debug, Clone, PartialEq, Eq)]
344pub struct AnnounceCancel {
345    /// The track namespace being cancelled.
346    pub track_namespace: TrackNamespace,
347    /// Application-defined error code.
348    pub error_code: VarInt,
349    /// Human-readable reason phrase.
350    pub reason_phrase: Vec<u8>,
351}
352
353/// UNANNOUNCE message (type 0x09).
354#[derive(Debug, Clone, PartialEq, Eq)]
355pub struct Unannounce {
356    /// The track namespace to unannounce.
357    pub track_namespace: TrackNamespace,
358}
359
360// ============================================================
361// Subscribe Announces Messages
362// ============================================================
363
364/// SUBSCRIBE_ANNOUNCES message (type 0x11).
365#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct SubscribeAnnounces {
367    /// The request ID for this subscription.
368    pub request_id: VarInt,
369    /// The track namespace prefix to subscribe to.
370    pub track_namespace_prefix: TrackNamespace,
371    /// Subscribe announces parameters (even/odd KVP encoding).
372    pub parameters: Vec<KeyValuePair>,
373}
374
375/// SUBSCRIBE_ANNOUNCES_OK message (type 0x12).
376#[derive(Debug, Clone, PartialEq, Eq)]
377pub struct SubscribeAnnouncesOk {
378    /// The request ID this response corresponds to.
379    pub request_id: VarInt,
380}
381
382/// SUBSCRIBE_ANNOUNCES_ERROR message (type 0x13).
383#[derive(Debug, Clone, PartialEq, Eq)]
384pub struct SubscribeAnnouncesError {
385    /// The request ID this error corresponds to.
386    pub request_id: VarInt,
387    /// Application-defined error code.
388    pub error_code: VarInt,
389    /// Human-readable reason phrase.
390    pub reason_phrase: Vec<u8>,
391}
392
393/// UNSUBSCRIBE_ANNOUNCES message (type 0x14).
394#[derive(Debug, Clone, PartialEq, Eq)]
395pub struct UnsubscribeAnnounces {
396    /// The track namespace prefix to unsubscribe from.
397    pub track_namespace_prefix: TrackNamespace,
398}
399
400// ============================================================
401// Track Status Messages
402// ============================================================
403
404/// TRACK_STATUS_REQUEST message (type 0x0D).
405#[derive(Debug, Clone, PartialEq, Eq)]
406pub struct TrackStatusRequest {
407    /// The request ID for this status query.
408    pub request_id: VarInt,
409    /// The track namespace to query.
410    pub track_namespace: TrackNamespace,
411    /// The track name within the namespace.
412    pub track_name: Vec<u8>,
413    /// Track status request parameters (even/odd KVP encoding).
414    pub parameters: Vec<KeyValuePair>,
415}
416
417/// TRACK_STATUS message (type 0x0E).
418#[derive(Debug, Clone, PartialEq, Eq)]
419pub struct TrackStatus {
420    /// The request ID this status corresponds to.
421    pub request_id: VarInt,
422    /// The track status code.
423    pub status_code: VarInt,
424    /// The largest location (always present in draft-11).
425    pub largest_location: Location,
426    /// Track status parameters (even/odd KVP encoding).
427    pub parameters: Vec<KeyValuePair>,
428}
429
430// ============================================================
431// Fetch Messages
432// ============================================================
433
434/// Fetch type discriminant.
435#[derive(Debug, Clone, Copy, PartialEq, Eq)]
436#[repr(u64)]
437pub enum FetchType {
438    /// Standalone fetch with full track + range.
439    Standalone = 1,
440    /// Joining fetch relative to a subscribe.
441    RelativeJoining = 2,
442    /// Joining fetch with absolute group start.
443    AbsoluteJoining = 3,
444}
445
446impl FetchType {
447    /// Convert a raw u64 to a `FetchType`, if valid.
448    pub fn from_u64(v: u64) -> Option<Self> {
449        match v {
450            1 => Some(FetchType::Standalone),
451            2 => Some(FetchType::RelativeJoining),
452            3 => Some(FetchType::AbsoluteJoining),
453            _ => None,
454        }
455    }
456}
457
458/// FETCH message (type 0x16).
459#[derive(Debug, Clone, PartialEq, Eq)]
460pub struct Fetch {
461    /// The request ID for this fetch.
462    pub request_id: VarInt,
463    /// Subscriber priority for delivery ordering.
464    pub subscriber_priority: u8,
465    /// Requested group delivery order.
466    pub group_order: GroupOrder,
467    /// The fetch type discriminant.
468    pub fetch_type: FetchType,
469    /// Fetch-type-specific payload.
470    pub fetch_payload: FetchPayload,
471    /// Fetch parameters (even/odd KVP encoding).
472    pub parameters: Vec<KeyValuePair>,
473}
474
475/// Fetch-type-specific payload fields.
476#[derive(Debug, Clone, PartialEq, Eq)]
477pub enum FetchPayload {
478    /// Standalone fetch (type 1).
479    Standalone {
480        /// The track namespace.
481        track_namespace: TrackNamespace,
482        /// The track name.
483        track_name: Vec<u8>,
484        /// Start group ID.
485        start_group: VarInt,
486        /// Start object ID.
487        start_object: VarInt,
488        /// End group ID.
489        end_group: VarInt,
490        /// End object ID.
491        end_object: VarInt,
492    },
493    /// Joining fetch (types 2 and 3).
494    Joining {
495        /// The subscribe request ID to join.
496        joining_subscribe_id: VarInt,
497        /// The joining start (offset for relative, group for absolute).
498        joining_start: VarInt,
499    },
500}
501
502/// FETCH_OK message (type 0x18).
503#[derive(Debug, Clone, PartialEq, Eq)]
504pub struct FetchOk {
505    /// The request ID this response corresponds to.
506    pub request_id: VarInt,
507    /// The group delivery order chosen by the publisher.
508    pub group_order: GroupOrder,
509    /// Whether the end of the track has been reached.
510    ///
511    /// Held as a raw byte rather than an enum: the draft describes 1 and 0 and
512    /// says nothing about any other value, where it does call an out-of-range
513    /// Group Order, Forward or Content Exists a protocol error. Refusing a 2
514    /// here would be this codec's rule and not the draft's.
515    pub end_of_track: u8,
516    /// The end location of the fetch response.
517    pub end_location: Location,
518    /// Response parameters (even/odd KVP encoding).
519    pub parameters: Vec<KeyValuePair>,
520}
521
522/// FETCH_ERROR message (type 0x19).
523#[derive(Debug, Clone, PartialEq, Eq)]
524pub struct FetchError {
525    /// The request ID this error corresponds to.
526    pub request_id: VarInt,
527    /// Application-defined error code.
528    pub error_code: VarInt,
529    /// Human-readable reason phrase.
530    pub reason_phrase: Vec<u8>,
531}
532
533/// FETCH_CANCEL message (type 0x17).
534#[derive(Debug, Clone, PartialEq, Eq)]
535pub struct FetchCancel {
536    /// The request ID of the fetch to cancel.
537    pub request_id: VarInt,
538}
539
540// ============================================================
541// Unified Message Enum
542// ============================================================
543
544/// Take one byte, or report the end of the buffer instead of panicking.
545fn read_u8(buf: &mut impl Buf) -> Result<u8, CodecError> {
546    if !buf.has_remaining() {
547        return Err(CodecError::UnexpectedEnd);
548    }
549    Ok(buf.get_u8())
550}
551
552/// Read a Group Order from a message that lets the publisher choose.
553///
554/// Every figure draws this field as a single byte, and the values are 0x1
555/// Ascending, 0x2 Descending, and 0x0 for "the original publisher's Group Order
556/// SHOULD be used".
557///
558/// Reading it as a varint instead is invisible for all three legal values —
559/// each is a single byte below 64, where the two encodings coincide — and
560/// diverges on everything a peer may send that is not legal. A two-byte varint
561/// holding 1 passes as Ascending and shifts every field after it, while the
562/// declared message length still adds up.
563fn read_group_order(buf: &mut impl Buf) -> Result<GroupOrder, CodecError> {
564    GroupOrder::from_u8(read_u8(buf)?).ok_or(CodecError::InvalidField)
565}
566
567/// Read a Forward flag: "Any other value is a protocol error and MUST terminate
568/// the session with a Protocol Violation"
569fn read_forward(buf: &mut impl Buf) -> Result<Forward, CodecError> {
570    match read_u8(buf)? {
571        0 => Ok(Forward::DontForward),
572        1 => Ok(Forward::Forward),
573        other => Err(CodecError::InvalidForward(other)),
574    }
575}
576
577/// Read a Content Exists flag, which carries the same sentence as Forward and
578/// also decides whether a Largest Location follows.
579fn read_content_exists(buf: &mut impl Buf) -> Result<ContentExists, CodecError> {
580    match read_u8(buf)? {
581        0 => Ok(ContentExists::NoLargestLocation),
582        1 => Ok(ContentExists::HasLargestLocation),
583        other => Err(CodecError::InvalidContentExists(other)),
584    }
585}
586
587/// Read a Group Order from a message that must name a real order.
588///
589/// SUBSCRIBE_OK and FETCH_OK each say
590/// "Values of 0x0 and those larger than 0x2 are a protocol error": a responder
591/// reports the order it settled on, so deferring to the publisher is not an
592/// answer it can give. SUBSCRIBE and FETCH are the requests, and there
593/// 0x0 is exactly how a subscriber says it has no preference — "the original
594/// publisher's Group Order SHOULD be used". The two readers cannot be merged
595/// without either refusing traffic the requests permit or accepting a reply
596/// that tells the subscriber nothing.
597fn read_group_order_response(buf: &mut impl Buf) -> Result<GroupOrder, CodecError> {
598    if !buf.has_remaining() {
599        return Err(CodecError::UnexpectedEnd);
600    }
601    match GroupOrder::from_u8(buf.get_u8()).ok_or(CodecError::InvalidField)? {
602        GroupOrder::Publisher => Err(CodecError::InvalidField),
603        order => Ok(order),
604    }
605}
606
607/// Both halves of a Start Location travel together, and only the two absolute
608/// filters put one on the wire. The Filter Type is still a raw varint on this
609/// draft, so the range check the decoder applies belongs here too.
610fn check_filter(
611    filter_type: VarInt,
612    start_group: &Option<VarInt>,
613    start_object: &Option<VarInt>,
614    end_group: &Option<VarInt>,
615) -> Result<(), CodecError> {
616    let value = filter_type.into_inner();
617    if value == 0 || value > 4 {
618        return Err(CodecError::InvalidFilterType(value));
619    }
620    let wants_start = value == 3 || value == 4;
621    if wants_start != start_group.is_some() || wants_start != start_object.is_some() {
622        return Err(CodecError::InvalidField);
623    }
624    if (value == 4) != end_group.is_some() {
625        return Err(CodecError::InvalidField);
626    }
627    Ok(())
628}
629
630fn check_content(
631    content_exists: ContentExists,
632    largest_location: &Option<Location>,
633) -> Result<(), CodecError> {
634    if (content_exists == ContentExists::HasLargestLocation) != largest_location.is_some() {
635        return Err(CodecError::InvalidField);
636    }
637    Ok(())
638}
639
640/// Hold a TRACK_STATUS Status Code and the fields after it to Section 8.18.
641///
642/// "Status Code: Provides additional information about the status of the track.
643/// It MUST hold one of the following values. Any other value is a malformed
644/// message." Two of those values - 0x01 and 0x02 - add "Subsequent fields MUST
645/// be zero, and any other value is a malformed message".
646///
647/// Applied on both sides. A malformed message is one this codec must not read
648/// and equally must not write: an encoder that emits an unassigned Status Code
649/// hands a conforming peer a message it is required to reject.
650fn check_track_status(status_code: VarInt, largest_location: Location) -> Result<(), CodecError> {
651    let code = crate::draft11::error_codes::TrackStatusCode::from_u64(status_code.into_inner())
652        .ok_or(CodecError::InvalidField)?;
653    if code.requires_zero_location()
654        && (largest_location.group.into_inner() != 0 || largest_location.object.into_inner() != 0)
655    {
656        return Err(CodecError::InvalidField);
657    }
658    Ok(())
659}
660
661/// Refuse a message whose optional fields disagree with the field that decides
662/// whether they are on the wire.
663///
664/// Presence is not a property of the Rust value: the decoder derives it from a
665/// Filter Type, a Content Exists flag or a Fetch Type, and reads exactly the
666/// fields that discriminator names. An encoder that instead writes whatever
667/// happens to be `Some` produces a frame its own reader refuses - short by the
668/// missing fields, so the declared length runs out mid-payload, or long by the
669/// surplus ones, so bytes are left over. Section 8 makes either a session
670/// close, which is why this refuses rather than papering over it.
671fn check_discriminators(message: &ControlMessage) -> Result<(), CodecError> {
672    match message {
673        ControlMessage::Subscribe(m) => {
674            check_filter(m.filter_type, &m.start_group, &m.start_object, &m.end_group)
675        }
676        ControlMessage::SubscribeOk(m) => check_content(m.content_exists, &m.largest_location),
677        ControlMessage::Fetch(m) => {
678            let body_is_standalone = matches!(m.fetch_payload, FetchPayload::Standalone { .. });
679            if body_is_standalone != (m.fetch_type == FetchType::Standalone) {
680                return Err(CodecError::InvalidField);
681            }
682            Ok(())
683        }
684        _ => Ok(()),
685    }
686}
687
688/// Refuse a Group Order of 0x0 on the messages that forbid it.
689///
690/// The decoders refuse it on the way in; without this the codec would still
691/// write a frame its own reader rejects.
692fn check_group_order(message: &ControlMessage) -> Result<(), CodecError> {
693    let order = match message {
694        ControlMessage::SubscribeOk(m) => m.group_order,
695        ControlMessage::FetchOk(m) => m.group_order,
696        _ => return Ok(()),
697    };
698    if order == GroupOrder::Publisher {
699        return Err(CodecError::InvalidField);
700    }
701    Ok(())
702}
703
704/// A parsed MoQT control message (draft-11).
705#[derive(Debug, Clone, PartialEq, Eq)]
706pub enum ControlMessage {
707    /// ClientSetup (type 0x20).
708    ClientSetup(ClientSetup),
709    /// ServerSetup (type 0x21).
710    ServerSetup(ServerSetup),
711    /// GoAway (type 0x10).
712    GoAway(GoAway),
713    /// MaxRequestId (type 0x15).
714    MaxRequestId(MaxRequestId),
715    /// RequestsBlocked (type 0x1A).
716    RequestsBlocked(RequestsBlocked),
717    /// Subscribe (type 0x03).
718    Subscribe(Subscribe),
719    /// SubscribeOk (type 0x04).
720    SubscribeOk(SubscribeOk),
721    /// SubscribeError (type 0x05).
722    SubscribeError(SubscribeError),
723    /// SubscribeUpdate (type 0x02).
724    SubscribeUpdate(SubscribeUpdate),
725    /// SubscribeDone (type 0x0B).
726    SubscribeDone(SubscribeDone),
727    /// Unsubscribe (type 0x0A).
728    Unsubscribe(Unsubscribe),
729    /// Announce (type 0x06).
730    Announce(Announce),
731    /// AnnounceOk (type 0x07).
732    AnnounceOk(AnnounceOk),
733    /// AnnounceError (type 0x08).
734    AnnounceError(AnnounceError),
735    /// AnnounceCancel (type 0x0C).
736    AnnounceCancel(AnnounceCancel),
737    /// Unannounce (type 0x09).
738    Unannounce(Unannounce),
739    /// SubscribeAnnounces (type 0x11).
740    SubscribeAnnounces(SubscribeAnnounces),
741    /// SubscribeAnnouncesOk (type 0x12).
742    SubscribeAnnouncesOk(SubscribeAnnouncesOk),
743    /// SubscribeAnnouncesError (type 0x13).
744    SubscribeAnnouncesError(SubscribeAnnouncesError),
745    /// UnsubscribeAnnounces (type 0x14).
746    UnsubscribeAnnounces(UnsubscribeAnnounces),
747    /// TrackStatusRequest (type 0x0D).
748    TrackStatusRequest(TrackStatusRequest),
749    /// TrackStatus (type 0x0E).
750    TrackStatus(TrackStatus),
751    /// Fetch (type 0x16).
752    Fetch(Fetch),
753    /// FetchOk (type 0x18).
754    FetchOk(FetchOk),
755    /// FetchError (type 0x19).
756    FetchError(FetchError),
757    /// FetchCancel (type 0x17).
758    FetchCancel(FetchCancel),
759}
760
761fn check_full_track_name(namespace: &TrackNamespace, track_name: &[u8]) -> Result<(), CodecError> {
762    let total = namespace.field_bytes_len().saturating_add(track_name.len());
763    if total > MAX_FULL_TRACK_NAME_LENGTH {
764        return Err(CodecError::TrackNameTooLong);
765    }
766    Ok(())
767}
768
769/// Read a Reason Phrase, holding it to the cap this draft states for a receiver.
770///
771/// "The reason phrase length has a maximum length of 1024 bytes. If an endpoint
772/// receives a length exceeding the maximum, it MUST close the session with a
773/// Protocol Violation". The sentence is about what an endpoint receives, and
774/// receiving was the direction the cap was not applied to: the encoders refused
775/// an over-long phrase and the decoders accepted one.
776fn read_reason_phrase(buf: &mut impl Buf) -> Result<Vec<u8>, CodecError> {
777    let len = VarInt::decode(buf)?.into_inner() as usize;
778    if len > MAX_REASON_PHRASE_LENGTH {
779        return Err(CodecError::ReasonPhraseTooLong);
780    }
781    types::read_bytes(buf, len)
782}
783
784/// Refuse a request whose range ends before it starts.
785///
786/// SUBSCRIBE's AbsoluteRange filter (Section 8.7), SUBSCRIBE_UPDATE
787/// (Section 8.10) and FETCH (Section 8.13) each state it, and the fields
788/// are not spelled the same way in the three places: an End Group is inclusive
789/// on SUBSCRIBE and FETCH and is the last group plus one on SUBSCRIBE_UPDATE,
790/// where zero means open ended, and an End Object is the last object plus one
791/// with zero meaning the whole group. The helpers this calls carry those
792/// conventions, one per shape.
793///
794/// Applied on both sides. A range that ends before it starts selects nothing,
795/// and the peer's only recourse is an error response or a session close, so
796/// writing one is not a way to ask for anything.
797fn check_ranges(message: &ControlMessage) -> Result<(), CodecError> {
798    match message {
799        ControlMessage::Subscribe(m) => match (&m.start_group, &m.end_group) {
800            (Some(start_group), Some(end_group)) => {
801                check_group_range(start_group.into_inner(), end_group.into_inner())
802            }
803            _ => Ok(()),
804        },
805        ControlMessage::SubscribeUpdate(m) => {
806            check_open_ended_group_range(m.start_group.into_inner(), m.end_group.into_inner())
807        }
808        ControlMessage::Fetch(m) => match &m.fetch_payload {
809            FetchPayload::Standalone {
810                start_group, start_object, end_group, end_object, ..
811            } => check_location_range(
812                start_group.into_inner(),
813                start_object.into_inner(),
814                end_group.into_inner(),
815                end_object.into_inner(),
816            ),
817            FetchPayload::Joining { .. } => Ok(()),
818        },
819        _ => Ok(()),
820    }
821}
822
823/// AUTHORIZATION TOKEN, the Version Specific Parameter of Section 8.2.1.1.
824///
825/// The number is this draft's own. Draft-11 assigns AUTHORIZATION TOKEN
826/// "Parameter Type 0x01"; drafts 12 and 13 move it to 0x03 and leave 0x01 to
827/// the setup-side PATH parameter. Reading either draft's number into the other
828/// would exempt the wrong type from the repeat rule below.
829const AUTHORIZATION_TOKEN: u64 = 0x01;
830
831/// DELIVERY TIMEOUT, the Version Specific Parameter of Section 8.2.1.2.
832const DELIVERY_TIMEOUT: u64 = 0x02;
833
834/// MAX_CACHE_DURATION, the Version Specific Parameter of Section 8.2.1.3.
835const MAX_CACHE_DURATION: u64 = 0x04;
836
837/// PATH, the Setup Parameter of Section 8.3.2.1.
838const SETUP_PATH: u64 = 0x01;
839
840/// MAX_REQUEST_ID, the Setup Parameter of Section 8.3.2.2.
841const SETUP_MAX_REQUEST_ID: u64 = 0x02;
842
843/// MAX_AUTH_TOKEN_CACHE_SIZE, the Setup Parameter of Section 8.3.2.3.
844const SETUP_MAX_AUTH_TOKEN_CACHE_SIZE: u64 = 0x04;
845
846/// Every Version Specific Parameter Type Section 8.2.1 names.
847///
848/// This list is what "unknown" means to the receiver's half of the Section 8.2
849/// rule. A type absent from it is one some extension defined, and Section 8.2
850/// requires a receiver to carry a repeat of such a type rather than refuse it.
851const KNOWN_PARAMETERS: &[u64] = &[AUTHORIZATION_TOKEN, DELIVERY_TIMEOUT, MAX_CACHE_DURATION];
852
853/// The Version Specific Parameter Types whose own definition allows a repeat.
854///
855/// Section 8.2.1.1: "The AUTHORIZATION TOKEN parameter MAY be repeated within a
856/// message." It is the only parameter on this draft that says so, and the
857/// exemption it earns holds on both sides.
858const REPEATABLE_PARAMETERS: &[u64] = &[AUTHORIZATION_TOKEN];
859
860/// Every Setup Parameter Type Section 8.3.2 names.
861const KNOWN_SETUP_PARAMETERS: &[u64] =
862    &[SETUP_PATH, SETUP_MAX_REQUEST_ID, SETUP_MAX_AUTH_TOKEN_CACHE_SIZE];
863
864/// The Setup Parameter Types whose own definition allows a repeat.
865///
866/// Draft-11 defines three Setup Parameters - PATH, MAX_REQUEST_ID and
867/// MAX_AUTH_TOKEN_CACHE_SIZE - and none of them says it may be repeated, so
868/// this namespace has no carve-out. Drafts 12 and 13 add AUTHORIZATION TOKEN to
869/// the setup side in Section 8.3.2.4 and gain one.
870///
871/// The two namespaces are kept apart because 0x01 means different things in
872/// each: AUTHORIZATION TOKEN among Version Specific Parameters, PATH among
873/// Setup Parameters. One shared exemption list would let a CLIENT_SETUP state
874/// PATH twice.
875const REPEATABLE_SETUP_PARAMETERS: &[u64] = &[];
876
877/// Refuse a parameter list a sender is not allowed to put on the wire.
878///
879/// Section 8.2: "Senders MUST NOT repeat the same parameter type in a message
880/// unless the parameter definition explicitly allows multiple instances of that
881/// type to be sent in a single message."
882///
883/// This is the wider half of the rule. It names no exception for types the
884/// sender does not recognise, so every repeat is refused here except the ones
885/// `repeatable` lists. A caller holding a parameter this codec has never heard
886/// of still may not send it twice: code that scans a parameter list for a key
887/// takes whichever copy it meets first, so one frame carrying two values for one
888/// type is read differently by two conforming implementations, and that is true
889/// whoever defined the type.
890fn check_sender_parameters(
891    parameters: &[KeyValuePair],
892    repeatable: &[u64],
893) -> Result<(), CodecError> {
894    for (i, parameter) in parameters.iter().enumerate() {
895        let key = parameter.key.into_inner();
896        if repeatable.contains(&key) {
897            continue;
898        }
899        if parameters[..i].iter().any(|earlier| earlier.key == parameter.key) {
900            return Err(CodecError::DuplicateParameter(key));
901        }
902    }
903    Ok(())
904}
905
906/// Refuse a received parameter list only where Section 8.2 lets a receiver
907/// refuse it.
908///
909/// Section 8.2: "Receivers SHOULD check that there are no unauthorized
910/// duplicate parameters and close the session as a 'Protocol Violation' if
911/// found. Receivers MUST allow duplicates of unknown parameters."
912///
913/// The second sentence is why this is not the mirror of
914/// [`check_sender_parameters`]: a repeat of a type this draft names is refused,
915/// and a repeat of any other type is carried. Making the two sides symmetric
916/// would close sessions over parameters defined by an extension this codec does
917/// not implement - traffic the draft requires an endpoint to tolerate - and the
918/// first sentence is a SHOULD, which does not reach that far.
919fn check_receiver_parameters(
920    parameters: &[KeyValuePair],
921    known: &[u64],
922    repeatable: &[u64],
923) -> Result<(), CodecError> {
924    for (i, parameter) in parameters.iter().enumerate() {
925        let key = parameter.key.into_inner();
926        if repeatable.contains(&key) || !known.contains(&key) {
927            continue;
928        }
929        if parameters[..i].iter().any(|earlier| earlier.key == parameter.key) {
930            return Err(CodecError::DuplicateParameter(key));
931        }
932    }
933    Ok(())
934}
935
936/// Hold every AUTHORIZATION TOKEN parameter to the Token structure it names.
937///
938/// Draft-11 states the general rule alone, in Section 1.3.2: "If a receiver
939/// understands a Type, and the following Value or Length/Value does not match
940/// the serialization defined by that Type, the receiver MUST terminate the
941/// session with error code 'Key-Value Formatting Error'." The Token is the one
942/// value in this draft whose serialization is a structure rather than opaque
943/// bytes, so it is the one the rule has anything to say about.
944///
945/// The type is 0x01 here, and only in the version-specific namespace. A setup
946/// 0x01 on this draft is a PATH, whose value is opaque bytes; reading one as a
947/// Token would refuse paths the draft permits. Draft-12 renumbered the token to
948/// 0x03 and added it to the setup namespace, where the two stop colliding.
949///
950/// A type this draft cannot name is left alone. The rule is conditional on the
951/// receiver understanding the Type, and an extension's parameter carries bytes
952/// no rule here describes.
953fn check_authorization_tokens(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
954    for parameter in parameters {
955        let key = parameter.key.into_inner();
956        if key != AUTH_TOKEN_PARAMETER_D11 {
957            continue;
958        }
959        match &parameter.value {
960            KvpValue::Bytes(value) => {
961                AuthorizationToken::decode(key, value)?;
962            }
963            // Unreachable from the decoder, which picks the shape from the
964            // type and finds this one length-prefixed. A caller that built the
965            // pair in memory can still get here, and it is the same rule: the
966            // value is not the serialization the type defines.
967            KvpValue::Varint(_) => {
968                return Err(CodecError::KeyValueFormatting {
969                    key,
970                    detail: "its value is a bare varint where the type defines a Token structure",
971                });
972            }
973        }
974    }
975    Ok(())
976}
977
978/// Decode a Version Specific Parameter list.
979fn decode_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
980    let parameters = KeyValuePair::decode_list(buf)?;
981    check_receiver_parameters(&parameters, KNOWN_PARAMETERS, REPEATABLE_PARAMETERS)?;
982    check_authorization_tokens(&parameters)?;
983    Ok(parameters)
984}
985
986/// Encode a Version Specific Parameter list.
987///
988/// The token structure is held to on the way out as well as on the way in. A
989/// value that is not the serialization its Type defines is one the receiver
990/// must close the session over, so writing it is not a way to send it — the
991/// sender's first sign of trouble would be the session going.
992///
993/// Version-specific parameters only, which is where this draft's 0x01 is the
994/// token; the setup 0x01 beside it is a PATH and its value is opaque bytes.
995fn encode_parameters(parameters: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
996    check_sender_parameters(parameters, REPEATABLE_PARAMETERS)?;
997    check_authorization_tokens(parameters)?;
998    KeyValuePair::encode_list_checked(parameters, buf)?;
999    Ok(())
1000}
1001
1002/// Decode the Setup Parameters of a CLIENT_SETUP or SERVER_SETUP message.
1003fn decode_setup_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
1004    let parameters = KeyValuePair::decode_list(buf)?;
1005    check_receiver_parameters(&parameters, KNOWN_SETUP_PARAMETERS, REPEATABLE_SETUP_PARAMETERS)?;
1006    Ok(parameters)
1007}
1008
1009/// Encode the Setup Parameters of a CLIENT_SETUP or SERVER_SETUP message.
1010fn encode_setup_parameters(
1011    parameters: &[KeyValuePair],
1012    buf: &mut impl BufMut,
1013) -> Result<(), CodecError> {
1014    check_sender_parameters(parameters, REPEATABLE_SETUP_PARAMETERS)?;
1015    KeyValuePair::encode_list_checked(parameters, buf)?;
1016    Ok(())
1017}
1018
1019impl ControlMessage {
1020    /// Encode this control message to bytes (including type ID and length prefix).
1021    ///
1022    /// Draft-11 framing: type_id(vi) + payload_length(16) + payload.
1023    pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
1024        check_discriminators(self)?;
1025        check_group_order(self)?;
1026        check_ranges(self)?;
1027        let mut payload = Vec::with_capacity(256);
1028        self.encode_payload(&mut payload)?;
1029
1030        if payload.len() > MAX_MESSAGE_LENGTH {
1031            return Err(CodecError::MessageTooLong(payload.len()));
1032        }
1033
1034        VarInt::from_usize(self.message_type().id() as usize).encode(buf);
1035        // Draft-11: 16-bit length (big-endian)
1036        buf.put_u16(payload.len() as u16);
1037        buf.put_slice(&payload);
1038        Ok(())
1039    }
1040
1041    /// Decode a control message from bytes (reads type ID and length prefix first).
1042    ///
1043    /// Draft-11 framing: type_id(vi) + payload_length(16) + payload.
1044    pub fn decode(buf: &mut impl Buf) -> Result<Self, CodecError> {
1045        let type_id = VarInt::decode(buf)?.into_inner();
1046        let msg_type =
1047            MessageType::from_id(type_id).ok_or(CodecError::UnknownMessageType(type_id))?;
1048        // Draft-11: 16-bit length (big-endian)
1049        if buf.remaining() < 2 {
1050            return Err(CodecError::UnexpectedEnd);
1051        }
1052        let payload_len = buf.get_u16() as usize;
1053        if buf.remaining() < payload_len {
1054            return Err(CodecError::UnexpectedEnd);
1055        }
1056        let payload_bytes = buf.copy_to_bytes(payload_len);
1057        let mut payload = &payload_bytes[..];
1058        let msg = match Self::decode_payload(msg_type, &mut payload) {
1059            Ok(msg) => msg,
1060            // The fields wanted more bytes than the Length allowed. This buffer
1061            // is already bounded by that Length, so running out inside it cannot
1062            // mean the message is still arriving - which is what the same error
1063            // means everywhere else, and why a reader loops on it rather than
1064            // closing. Here there is nothing left to arrive.
1065            Err(
1066                CodecError::UnexpectedEnd
1067                | CodecError::Kvp(crate::kvp::KvpError::UnexpectedEnd)
1068                | CodecError::Kvp(crate::kvp::KvpError::VarInt(
1069                    crate::varint::VarIntError::UnexpectedEnd,
1070                ))
1071                | CodecError::VarInt(crate::varint::VarIntError::UnexpectedEnd),
1072            ) => {
1073                return Err(CodecError::ControlMessageLengthMismatch {
1074                    declared: payload_len,
1075                    detail: "its fields ran past the end",
1076                });
1077            }
1078            Err(e) => return Err(e),
1079        };
1080        check_ranges(&msg)?;
1081        // The declared length is part of the message, not a hint. Bytes left over
1082        // after the fields have been read mean the sender and this reader disagree
1083        // about the shape of the message, and guessing which of the two is right
1084        // is how a trailing field gets silently dropped.
1085        if payload.has_remaining() {
1086            return Err(CodecError::ControlMessageLengthMismatch {
1087                declared: payload_len,
1088                detail: "its fields left bytes unread",
1089            });
1090        }
1091        Ok(msg)
1092    }
1093
1094    fn encode_payload(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
1095        match self {
1096            ControlMessage::ClientSetup(m) => {
1097                VarInt::from_usize(m.supported_versions.len()).encode(buf);
1098                for v in &m.supported_versions {
1099                    v.encode(buf);
1100                }
1101                encode_setup_parameters(&m.parameters, buf)?;
1102            }
1103            ControlMessage::ServerSetup(m) => {
1104                m.selected_version.encode(buf);
1105                encode_setup_parameters(&m.parameters, buf)?;
1106            }
1107            ControlMessage::GoAway(m) => {
1108                if m.new_session_uri.len() > MAX_GOAWAY_URI_LENGTH {
1109                    return Err(CodecError::GoAwayUriTooLong);
1110                }
1111                VarInt::from_usize(m.new_session_uri.len()).encode(buf);
1112                buf.put_slice(&m.new_session_uri);
1113            }
1114            ControlMessage::MaxRequestId(m) => {
1115                m.request_id.encode(buf);
1116            }
1117            ControlMessage::RequestsBlocked(m) => {
1118                m.maximum_request_id.encode(buf);
1119            }
1120            ControlMessage::Subscribe(m) => {
1121                m.request_id.encode(buf);
1122                m.track_alias.encode(buf);
1123                m.track_namespace.validate(TrackNamespaceRules::for_draft(11))?;
1124                m.track_namespace.encode(buf);
1125                check_full_track_name(&m.track_namespace, &m.track_name)?;
1126                VarInt::from_usize(m.track_name.len()).encode(buf);
1127                buf.put_slice(&m.track_name);
1128                buf.put_u8(m.subscriber_priority);
1129                buf.put_u8(m.group_order as u8);
1130                buf.put_u8(m.forward as u8);
1131                m.filter_type.encode(buf);
1132                if let Some(sg) = &m.start_group {
1133                    sg.encode(buf);
1134                }
1135                if let Some(so) = &m.start_object {
1136                    so.encode(buf);
1137                }
1138                if let Some(eg) = &m.end_group {
1139                    eg.encode(buf);
1140                }
1141                encode_parameters(&m.parameters, buf)?;
1142            }
1143            ControlMessage::SubscribeOk(m) => {
1144                m.request_id.encode(buf);
1145                m.expires.encode(buf);
1146                buf.put_u8(m.group_order as u8);
1147                buf.put_u8(m.content_exists as u8);
1148                if let Some(loc) = &m.largest_location {
1149                    loc.encode(buf);
1150                }
1151                encode_parameters(&m.parameters, buf)?;
1152            }
1153            ControlMessage::SubscribeError(m) => {
1154                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1155                    return Err(CodecError::ReasonPhraseTooLong);
1156                }
1157                m.request_id.encode(buf);
1158                m.error_code.encode(buf);
1159                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1160                buf.put_slice(&m.reason_phrase);
1161                m.track_alias.encode(buf);
1162            }
1163            ControlMessage::SubscribeUpdate(m) => {
1164                m.request_id.encode(buf);
1165                m.start_group.encode(buf);
1166                m.start_object.encode(buf);
1167                m.end_group.encode(buf);
1168                buf.put_u8(m.subscriber_priority);
1169                buf.put_u8(m.forward as u8);
1170                encode_parameters(&m.parameters, buf)?;
1171            }
1172            ControlMessage::SubscribeDone(m) => {
1173                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1174                    return Err(CodecError::ReasonPhraseTooLong);
1175                }
1176                m.request_id.encode(buf);
1177                m.status_code.encode(buf);
1178                m.stream_count.encode(buf);
1179                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1180                buf.put_slice(&m.reason_phrase);
1181            }
1182            ControlMessage::Unsubscribe(m) => {
1183                m.request_id.encode(buf);
1184            }
1185            ControlMessage::Announce(m) => {
1186                m.request_id.encode(buf);
1187                m.track_namespace.validate(TrackNamespaceRules::for_draft(11))?;
1188                m.track_namespace.encode(buf);
1189                encode_parameters(&m.parameters, buf)?;
1190            }
1191            ControlMessage::AnnounceOk(m) => {
1192                m.request_id.encode(buf);
1193            }
1194            ControlMessage::AnnounceError(m) => {
1195                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1196                    return Err(CodecError::ReasonPhraseTooLong);
1197                }
1198                m.request_id.encode(buf);
1199                m.error_code.encode(buf);
1200                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1201                buf.put_slice(&m.reason_phrase);
1202            }
1203            ControlMessage::AnnounceCancel(m) => {
1204                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1205                    return Err(CodecError::ReasonPhraseTooLong);
1206                }
1207                m.track_namespace.validate(TrackNamespaceRules::for_draft(11))?;
1208                m.track_namespace.encode(buf);
1209                m.error_code.encode(buf);
1210                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1211                buf.put_slice(&m.reason_phrase);
1212            }
1213            ControlMessage::Unannounce(m) => {
1214                m.track_namespace.validate(TrackNamespaceRules::for_draft(11))?;
1215                m.track_namespace.encode(buf);
1216            }
1217            ControlMessage::SubscribeAnnounces(m) => {
1218                m.request_id.encode(buf);
1219                m.track_namespace_prefix.validate(TrackNamespaceRules::for_draft(11))?;
1220                m.track_namespace_prefix.encode(buf);
1221                encode_parameters(&m.parameters, buf)?;
1222            }
1223            ControlMessage::SubscribeAnnouncesOk(m) => {
1224                m.request_id.encode(buf);
1225            }
1226            ControlMessage::SubscribeAnnouncesError(m) => {
1227                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1228                    return Err(CodecError::ReasonPhraseTooLong);
1229                }
1230                m.request_id.encode(buf);
1231                m.error_code.encode(buf);
1232                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1233                buf.put_slice(&m.reason_phrase);
1234            }
1235            ControlMessage::UnsubscribeAnnounces(m) => {
1236                m.track_namespace_prefix.validate(TrackNamespaceRules::for_draft(11))?;
1237                m.track_namespace_prefix.encode(buf);
1238            }
1239            ControlMessage::TrackStatusRequest(m) => {
1240                m.request_id.encode(buf);
1241                m.track_namespace.validate(TrackNamespaceRules::for_draft(11))?;
1242                m.track_namespace.encode(buf);
1243                check_full_track_name(&m.track_namespace, &m.track_name)?;
1244                VarInt::from_usize(m.track_name.len()).encode(buf);
1245                buf.put_slice(&m.track_name);
1246                encode_parameters(&m.parameters, buf)?;
1247            }
1248            ControlMessage::TrackStatus(m) => {
1249                m.request_id.encode(buf);
1250                check_track_status(m.status_code, m.largest_location)?;
1251                m.status_code.encode(buf);
1252                m.largest_location.encode(buf);
1253                encode_parameters(&m.parameters, buf)?;
1254            }
1255            ControlMessage::Fetch(m) => {
1256                m.request_id.encode(buf);
1257                buf.put_u8(m.subscriber_priority);
1258                buf.put_u8(m.group_order as u8);
1259                VarInt::from_usize(m.fetch_type as usize).encode(buf);
1260                match &m.fetch_payload {
1261                    FetchPayload::Standalone {
1262                        track_namespace,
1263                        track_name,
1264                        start_group,
1265                        start_object,
1266                        end_group,
1267                        end_object,
1268                    } => {
1269                        track_namespace.validate(TrackNamespaceRules::for_draft(11))?;
1270                        track_namespace.encode(buf);
1271                        check_full_track_name(track_namespace, track_name)?;
1272                        VarInt::from_usize(track_name.len()).encode(buf);
1273                        buf.put_slice(track_name);
1274                        start_group.encode(buf);
1275                        start_object.encode(buf);
1276                        end_group.encode(buf);
1277                        end_object.encode(buf);
1278                    }
1279                    FetchPayload::Joining { joining_subscribe_id, joining_start } => {
1280                        joining_subscribe_id.encode(buf);
1281                        joining_start.encode(buf);
1282                    }
1283                }
1284                encode_parameters(&m.parameters, buf)?;
1285            }
1286            ControlMessage::FetchOk(m) => {
1287                m.request_id.encode(buf);
1288                buf.put_u8(m.group_order as u8);
1289                buf.put_u8(m.end_of_track);
1290                m.end_location.encode(buf);
1291                encode_parameters(&m.parameters, buf)?;
1292            }
1293            ControlMessage::FetchError(m) => {
1294                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1295                    return Err(CodecError::ReasonPhraseTooLong);
1296                }
1297                m.request_id.encode(buf);
1298                m.error_code.encode(buf);
1299                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1300                buf.put_slice(&m.reason_phrase);
1301            }
1302            ControlMessage::FetchCancel(m) => {
1303                m.request_id.encode(buf);
1304            }
1305        }
1306        Ok(())
1307    }
1308
1309    fn decode_payload(msg_type: MessageType, buf: &mut impl Buf) -> Result<Self, CodecError> {
1310        match msg_type {
1311            MessageType::ClientSetup => {
1312                let num_versions = VarInt::decode(buf)?.into_inner() as usize;
1313                // Not a rule this draft states. It says only that the server
1314                // "MUST reply with one of the versions offered by the client"
1315                // and that a peer with no version in common "MUST close the
1316                // session" - outcomes of negotiation rather than parse errors,
1317                // and a CLIENT_SETUP offering nothing decodes cleanly under the
1318                // figure. It is refused here because there is no version a
1319                // reply could name, so the session is already over and the
1320                // early close is the more useful answer than a well-formed
1321                // message no caller can act on.
1322                if num_versions == 0 {
1323                    return Err(CodecError::InvalidField);
1324                }
1325                let mut supported_versions = crate::types::reserve_bounded(num_versions, buf);
1326                for _ in 0..num_versions {
1327                    supported_versions.push(VarInt::decode(buf)?);
1328                }
1329                let parameters = decode_setup_parameters(buf)?;
1330                Ok(ControlMessage::ClientSetup(ClientSetup { supported_versions, parameters }))
1331            }
1332            MessageType::ServerSetup => {
1333                let selected_version = VarInt::decode(buf)?;
1334                let parameters = decode_setup_parameters(buf)?;
1335                Ok(ControlMessage::ServerSetup(ServerSetup { selected_version, parameters }))
1336            }
1337            MessageType::GoAway => {
1338                let uri_len = VarInt::decode(buf)?.into_inner() as usize;
1339                if uri_len > MAX_GOAWAY_URI_LENGTH {
1340                    return Err(CodecError::GoAwayUriTooLong);
1341                }
1342                let uri = types::read_bytes(buf, uri_len)?;
1343                Ok(ControlMessage::GoAway(GoAway { new_session_uri: uri }))
1344            }
1345            MessageType::MaxRequestId => {
1346                let request_id = VarInt::decode(buf)?;
1347                Ok(ControlMessage::MaxRequestId(MaxRequestId { request_id }))
1348            }
1349            MessageType::RequestsBlocked => {
1350                let maximum_request_id = VarInt::decode(buf)?;
1351                Ok(ControlMessage::RequestsBlocked(RequestsBlocked { maximum_request_id }))
1352            }
1353            MessageType::Subscribe => {
1354                let request_id = VarInt::decode(buf)?;
1355                let track_alias = VarInt::decode(buf)?;
1356                let track_namespace = TrackNamespace::decode(buf)?;
1357                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1358                let track_name = types::read_bytes(buf, track_name_len)?;
1359                check_full_track_name(&track_namespace, &track_name)?;
1360                if buf.remaining() < 1 {
1361                    return Err(CodecError::UnexpectedEnd);
1362                }
1363                let subscriber_priority = buf.get_u8();
1364                let group_order = read_group_order(buf)?;
1365                let forward = read_forward(buf)?;
1366                let filter_type = VarInt::decode(buf)?;
1367                let ft_val = filter_type.into_inner();
1368                if ft_val == 0 || ft_val > 4 {
1369                    return Err(CodecError::InvalidFilterType(ft_val));
1370                }
1371                let (start_group, start_object) = if ft_val == 3 || ft_val == 4 {
1372                    (Some(VarInt::decode(buf)?), Some(VarInt::decode(buf)?))
1373                } else {
1374                    (None, None)
1375                };
1376                let end_group = if ft_val == 4 { Some(VarInt::decode(buf)?) } else { None };
1377                let parameters = decode_parameters(buf)?;
1378                Ok(ControlMessage::Subscribe(Subscribe {
1379                    request_id,
1380                    track_alias,
1381                    track_namespace,
1382                    track_name,
1383                    subscriber_priority,
1384                    group_order,
1385                    forward,
1386                    filter_type,
1387                    start_group,
1388                    start_object,
1389                    end_group,
1390                    parameters,
1391                }))
1392            }
1393            MessageType::SubscribeOk => {
1394                let request_id = VarInt::decode(buf)?;
1395                let expires = VarInt::decode(buf)?;
1396                let group_order = read_group_order_response(buf)?;
1397                let content_exists = read_content_exists(buf)?;
1398                let largest_location = if content_exists == ContentExists::HasLargestLocation {
1399                    Some(Location::decode(buf)?)
1400                } else {
1401                    None
1402                };
1403                let parameters = decode_parameters(buf)?;
1404                Ok(ControlMessage::SubscribeOk(SubscribeOk {
1405                    request_id,
1406                    expires,
1407                    group_order,
1408                    content_exists,
1409                    largest_location,
1410                    parameters,
1411                }))
1412            }
1413            MessageType::SubscribeError => {
1414                let request_id = VarInt::decode(buf)?;
1415                let error_code = VarInt::decode(buf)?;
1416                let reason_phrase = read_reason_phrase(buf)?;
1417                let track_alias = VarInt::decode(buf)?;
1418                Ok(ControlMessage::SubscribeError(SubscribeError {
1419                    request_id,
1420                    error_code,
1421                    reason_phrase,
1422                    track_alias,
1423                }))
1424            }
1425            MessageType::SubscribeUpdate => {
1426                let request_id = VarInt::decode(buf)?;
1427                let start_group = VarInt::decode(buf)?;
1428                let start_object = VarInt::decode(buf)?;
1429                let end_group = VarInt::decode(buf)?;
1430                if buf.remaining() < 1 {
1431                    return Err(CodecError::UnexpectedEnd);
1432                }
1433                let subscriber_priority = buf.get_u8();
1434                let forward = read_forward(buf)?;
1435                let parameters = decode_parameters(buf)?;
1436                Ok(ControlMessage::SubscribeUpdate(SubscribeUpdate {
1437                    request_id,
1438                    start_group,
1439                    start_object,
1440                    end_group,
1441                    subscriber_priority,
1442                    forward,
1443                    parameters,
1444                }))
1445            }
1446            MessageType::SubscribeDone => {
1447                let request_id = VarInt::decode(buf)?;
1448                let status_code = VarInt::decode(buf)?;
1449                let stream_count = VarInt::decode(buf)?;
1450                let reason_phrase = read_reason_phrase(buf)?;
1451                Ok(ControlMessage::SubscribeDone(SubscribeDone {
1452                    request_id,
1453                    status_code,
1454                    stream_count,
1455                    reason_phrase,
1456                }))
1457            }
1458            MessageType::Unsubscribe => {
1459                let request_id = VarInt::decode(buf)?;
1460                Ok(ControlMessage::Unsubscribe(Unsubscribe { request_id }))
1461            }
1462            MessageType::Announce => {
1463                let request_id = VarInt::decode(buf)?;
1464                let track_namespace = TrackNamespace::decode(buf)?;
1465                let parameters = decode_parameters(buf)?;
1466                Ok(ControlMessage::Announce(Announce { request_id, track_namespace, parameters }))
1467            }
1468            MessageType::AnnounceOk => {
1469                let request_id = VarInt::decode(buf)?;
1470                Ok(ControlMessage::AnnounceOk(AnnounceOk { request_id }))
1471            }
1472            MessageType::AnnounceError => {
1473                let request_id = VarInt::decode(buf)?;
1474                let error_code = VarInt::decode(buf)?;
1475                let reason_phrase = read_reason_phrase(buf)?;
1476                Ok(ControlMessage::AnnounceError(AnnounceError {
1477                    request_id,
1478                    error_code,
1479                    reason_phrase,
1480                }))
1481            }
1482            MessageType::AnnounceCancel => {
1483                let track_namespace = TrackNamespace::decode(buf)?;
1484                let error_code = VarInt::decode(buf)?;
1485                let reason_phrase = read_reason_phrase(buf)?;
1486                Ok(ControlMessage::AnnounceCancel(AnnounceCancel {
1487                    track_namespace,
1488                    error_code,
1489                    reason_phrase,
1490                }))
1491            }
1492            MessageType::Unannounce => {
1493                let track_namespace = TrackNamespace::decode(buf)?;
1494                Ok(ControlMessage::Unannounce(Unannounce { track_namespace }))
1495            }
1496            MessageType::SubscribeAnnounces => {
1497                let request_id = VarInt::decode(buf)?;
1498                let track_namespace_prefix = TrackNamespace::decode(buf)?;
1499                let parameters = decode_parameters(buf)?;
1500                Ok(ControlMessage::SubscribeAnnounces(SubscribeAnnounces {
1501                    request_id,
1502                    track_namespace_prefix,
1503                    parameters,
1504                }))
1505            }
1506            MessageType::SubscribeAnnouncesOk => {
1507                let request_id = VarInt::decode(buf)?;
1508                Ok(ControlMessage::SubscribeAnnouncesOk(SubscribeAnnouncesOk { request_id }))
1509            }
1510            MessageType::SubscribeAnnouncesError => {
1511                let request_id = VarInt::decode(buf)?;
1512                let error_code = VarInt::decode(buf)?;
1513                let reason_phrase = read_reason_phrase(buf)?;
1514                Ok(ControlMessage::SubscribeAnnouncesError(SubscribeAnnouncesError {
1515                    request_id,
1516                    error_code,
1517                    reason_phrase,
1518                }))
1519            }
1520            MessageType::UnsubscribeAnnounces => {
1521                let track_namespace_prefix = TrackNamespace::decode(buf)?;
1522                Ok(ControlMessage::UnsubscribeAnnounces(UnsubscribeAnnounces {
1523                    track_namespace_prefix,
1524                }))
1525            }
1526            MessageType::TrackStatusRequest => {
1527                let request_id = VarInt::decode(buf)?;
1528                let track_namespace = TrackNamespace::decode(buf)?;
1529                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1530                let track_name = types::read_bytes(buf, track_name_len)?;
1531                check_full_track_name(&track_namespace, &track_name)?;
1532                let parameters = decode_parameters(buf)?;
1533                Ok(ControlMessage::TrackStatusRequest(TrackStatusRequest {
1534                    request_id,
1535                    track_namespace,
1536                    track_name,
1537                    parameters,
1538                }))
1539            }
1540            MessageType::TrackStatus => {
1541                let request_id = VarInt::decode(buf)?;
1542                let status_code = VarInt::decode(buf)?;
1543                let largest_location = Location::decode(buf)?;
1544                check_track_status(status_code, largest_location)?;
1545                let parameters = decode_parameters(buf)?;
1546                Ok(ControlMessage::TrackStatus(TrackStatus {
1547                    request_id,
1548                    status_code,
1549                    largest_location,
1550                    parameters,
1551                }))
1552            }
1553            MessageType::Fetch => {
1554                let request_id = VarInt::decode(buf)?;
1555                if buf.remaining() < 1 {
1556                    return Err(CodecError::UnexpectedEnd);
1557                }
1558                let subscriber_priority = buf.get_u8();
1559                let group_order = read_group_order(buf)?;
1560                let fetch_type_val = VarInt::decode(buf)?.into_inner();
1561                let fetch_type = FetchType::from_u64(fetch_type_val)
1562                    .ok_or(CodecError::InvalidFetchType(fetch_type_val))?;
1563                let fetch_payload = match fetch_type {
1564                    FetchType::Standalone => {
1565                        let track_namespace = TrackNamespace::decode(buf)?;
1566                        let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1567                        let track_name = types::read_bytes(buf, track_name_len)?;
1568                        check_full_track_name(&track_namespace, &track_name)?;
1569                        let start_group = VarInt::decode(buf)?;
1570                        let start_object = VarInt::decode(buf)?;
1571                        let end_group = VarInt::decode(buf)?;
1572                        let end_object = VarInt::decode(buf)?;
1573                        FetchPayload::Standalone {
1574                            track_namespace,
1575                            track_name,
1576                            start_group,
1577                            start_object,
1578                            end_group,
1579                            end_object,
1580                        }
1581                    }
1582                    FetchType::RelativeJoining | FetchType::AbsoluteJoining => {
1583                        let joining_subscribe_id = VarInt::decode(buf)?;
1584                        let joining_start = VarInt::decode(buf)?;
1585                        FetchPayload::Joining { joining_subscribe_id, joining_start }
1586                    }
1587                };
1588                let parameters = decode_parameters(buf)?;
1589                Ok(ControlMessage::Fetch(Fetch {
1590                    request_id,
1591                    subscriber_priority,
1592                    group_order,
1593                    fetch_type,
1594                    fetch_payload,
1595                    parameters,
1596                }))
1597            }
1598            MessageType::FetchOk => {
1599                let request_id = VarInt::decode(buf)?;
1600                let group_order = read_group_order_response(buf)?;
1601                let end_of_track = read_u8(buf)?;
1602                let end_location = Location::decode(buf)?;
1603                let parameters = decode_parameters(buf)?;
1604                Ok(ControlMessage::FetchOk(FetchOk {
1605                    request_id,
1606                    group_order,
1607                    end_of_track,
1608                    end_location,
1609                    parameters,
1610                }))
1611            }
1612            MessageType::FetchError => {
1613                let request_id = VarInt::decode(buf)?;
1614                let error_code = VarInt::decode(buf)?;
1615                let reason_phrase = read_reason_phrase(buf)?;
1616                Ok(ControlMessage::FetchError(FetchError { request_id, error_code, reason_phrase }))
1617            }
1618            MessageType::FetchCancel => {
1619                let request_id = VarInt::decode(buf)?;
1620                Ok(ControlMessage::FetchCancel(FetchCancel { request_id }))
1621            }
1622        }
1623    }
1624
1625    /// Get the message type ID for this message.
1626    pub fn message_type(&self) -> MessageType {
1627        match self {
1628            ControlMessage::ClientSetup(_) => MessageType::ClientSetup,
1629            ControlMessage::ServerSetup(_) => MessageType::ServerSetup,
1630            ControlMessage::GoAway(_) => MessageType::GoAway,
1631            ControlMessage::MaxRequestId(_) => MessageType::MaxRequestId,
1632            ControlMessage::RequestsBlocked(_) => MessageType::RequestsBlocked,
1633            ControlMessage::Subscribe(_) => MessageType::Subscribe,
1634            ControlMessage::SubscribeOk(_) => MessageType::SubscribeOk,
1635            ControlMessage::SubscribeError(_) => MessageType::SubscribeError,
1636            ControlMessage::SubscribeUpdate(_) => MessageType::SubscribeUpdate,
1637            ControlMessage::SubscribeDone(_) => MessageType::SubscribeDone,
1638            ControlMessage::Unsubscribe(_) => MessageType::Unsubscribe,
1639            ControlMessage::Announce(_) => MessageType::Announce,
1640            ControlMessage::AnnounceOk(_) => MessageType::AnnounceOk,
1641            ControlMessage::AnnounceError(_) => MessageType::AnnounceError,
1642            ControlMessage::AnnounceCancel(_) => MessageType::AnnounceCancel,
1643            ControlMessage::Unannounce(_) => MessageType::Unannounce,
1644            ControlMessage::SubscribeAnnounces(_) => MessageType::SubscribeAnnounces,
1645            ControlMessage::SubscribeAnnouncesOk(_) => MessageType::SubscribeAnnouncesOk,
1646            ControlMessage::SubscribeAnnouncesError(_) => MessageType::SubscribeAnnouncesError,
1647            ControlMessage::UnsubscribeAnnounces(_) => MessageType::UnsubscribeAnnounces,
1648            ControlMessage::TrackStatusRequest(_) => MessageType::TrackStatusRequest,
1649            ControlMessage::TrackStatus(_) => MessageType::TrackStatus,
1650            ControlMessage::Fetch(_) => MessageType::Fetch,
1651            ControlMessage::FetchOk(_) => MessageType::FetchOk,
1652            ControlMessage::FetchError(_) => MessageType::FetchError,
1653            ControlMessage::FetchCancel(_) => MessageType::FetchCancel,
1654        }
1655    }
1656}