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