Skip to main content

moqtap_codec/draft13/
message.rs

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