Skip to main content

moqtap_codec/draft15/
message.rs

1//! Draft-15 control message encoding and decoding.
2//!
3//! Key changes from draft-14:
4//! - Version negotiation via ALPN — ClientSetup/ServerSetup have no versions
5//! - Consolidated RequestOk (0x07) and RequestError (0x05)
6//! - Subscribe simplified: request_id + ns + track_name + params
7//! - SubscribeOk simplified: request_id + track_alias + params
8//! - Publish simplified: request_id + ns + track_name + track_alias + params
9//! - PublishOk simplified: request_id + params
10//! - SubscribeUpdate: request_id + subscription_request_id + params
11//! - FetchOk: request_id + end_of_track + end_group + end_object + params
12//! - PublishDone (0x0B) replaces SubscribeDone
13//! - Framing: type_id(vi) + payload_length(16) + payload
14
15use crate::auth_token::{AuthorizationToken, AUTH_TOKEN_PARAMETER};
16use crate::error::{
17    CodecError, MAX_FULL_TRACK_NAME_LENGTH, MAX_GOAWAY_URI_LENGTH, MAX_MESSAGE_LENGTH,
18    MAX_REASON_PHRASE_LENGTH,
19};
20use crate::kvp::{KeyValuePair, KvpValue};
21use crate::subscription_filter::{SubscriptionFilter, SUBSCRIPTION_FILTER_PARAMETER};
22pub use crate::types::check_location_range;
23use crate::types::*;
24use crate::varint::VarInt;
25use bytes::{Buf, BufMut};
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[repr(u64)]
29pub enum MessageType {
30    SubscribeUpdate = 0x02,
31    Subscribe = 0x03,
32    SubscribeOk = 0x04,
33    RequestError = 0x05,
34    PublishNamespace = 0x06,
35    RequestOk = 0x07,
36    PublishNamespaceDone = 0x09,
37    Unsubscribe = 0x0A,
38    PublishDone = 0x0B,
39    PublishNamespaceCancel = 0x0C,
40    TrackStatus = 0x0D,
41    GoAway = 0x10,
42    SubscribeNamespace = 0x11,
43    UnsubscribeNamespace = 0x14,
44    MaxRequestId = 0x15,
45    Fetch = 0x16,
46    FetchCancel = 0x17,
47    FetchOk = 0x18,
48    RequestsBlocked = 0x1A,
49    Publish = 0x1D,
50    PublishOk = 0x1E,
51    ClientSetup = 0x20,
52    ServerSetup = 0x21,
53}
54
55impl MessageType {
56    pub fn from_id(id: u64) -> Option<Self> {
57        match id {
58            0x02 => Some(MessageType::SubscribeUpdate),
59            0x03 => Some(MessageType::Subscribe),
60            0x04 => Some(MessageType::SubscribeOk),
61            0x05 => Some(MessageType::RequestError),
62            0x06 => Some(MessageType::PublishNamespace),
63            0x07 => Some(MessageType::RequestOk),
64            0x09 => Some(MessageType::PublishNamespaceDone),
65            0x0A => Some(MessageType::Unsubscribe),
66            0x0B => Some(MessageType::PublishDone),
67            0x0C => Some(MessageType::PublishNamespaceCancel),
68            0x0D => Some(MessageType::TrackStatus),
69            0x10 => Some(MessageType::GoAway),
70            0x11 => Some(MessageType::SubscribeNamespace),
71            0x14 => Some(MessageType::UnsubscribeNamespace),
72            0x15 => Some(MessageType::MaxRequestId),
73            0x16 => Some(MessageType::Fetch),
74            0x17 => Some(MessageType::FetchCancel),
75            0x18 => Some(MessageType::FetchOk),
76            0x1A => Some(MessageType::RequestsBlocked),
77            0x1D => Some(MessageType::Publish),
78            0x1E => Some(MessageType::PublishOk),
79            0x20 => Some(MessageType::ClientSetup),
80            0x21 => Some(MessageType::ServerSetup),
81            _ => None,
82        }
83    }
84
85    pub fn id(&self) -> u64 {
86        *self as u64
87    }
88
89    /// This type's name in the shared vector corpus: the `message_type` its
90    /// draft's `codec/messages/*.json` files carry, in `snake_case`.
91    pub fn name(&self) -> &'static str {
92        match self {
93            MessageType::SubscribeUpdate => "subscribe_update",
94            MessageType::Subscribe => "subscribe",
95            MessageType::SubscribeOk => "subscribe_ok",
96            MessageType::RequestError => "request_error",
97            MessageType::PublishNamespace => "publish_namespace",
98            MessageType::RequestOk => "request_ok",
99            MessageType::PublishNamespaceDone => "publish_namespace_done",
100            MessageType::Unsubscribe => "unsubscribe",
101            MessageType::PublishDone => "publish_done",
102            MessageType::PublishNamespaceCancel => "publish_namespace_cancel",
103            MessageType::TrackStatus => "track_status",
104            MessageType::GoAway => "goaway",
105            MessageType::SubscribeNamespace => "subscribe_namespace",
106            MessageType::UnsubscribeNamespace => "unsubscribe_namespace",
107            MessageType::MaxRequestId => "max_request_id",
108            MessageType::Fetch => "fetch",
109            MessageType::FetchCancel => "fetch_cancel",
110            MessageType::FetchOk => "fetch_ok",
111            MessageType::RequestsBlocked => "requests_blocked",
112            MessageType::Publish => "publish",
113            MessageType::PublishOk => "publish_ok",
114            MessageType::ClientSetup => "client_setup",
115            MessageType::ServerSetup => "server_setup",
116        }
117    }
118}
119
120// ============================================================
121// Session Lifecycle Messages
122// ============================================================
123
124/// CLIENT_SETUP (0x20). Draft-15: no versions, just parameters.
125#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct ClientSetup {
127    pub parameters: Vec<KeyValuePair>,
128}
129
130/// SERVER_SETUP (0x21). Draft-15: no version, just parameters.
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct ServerSetup {
133    pub parameters: Vec<KeyValuePair>,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct GoAway {
138    pub new_session_uri: Vec<u8>,
139}
140
141#[derive(Debug, Clone, PartialEq, Eq)]
142pub struct MaxRequestId {
143    pub request_id: VarInt,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct RequestsBlocked {
148    pub maximum_request_id: VarInt,
149}
150
151// ============================================================
152// Consolidated Response Messages
153// ============================================================
154
155/// REQUEST_OK (0x07). Consolidated OK response for all request types.
156#[derive(Debug, Clone, PartialEq, Eq)]
157pub struct RequestOk {
158    pub request_id: VarInt,
159    pub parameters: Vec<KeyValuePair>,
160}
161
162/// REQUEST_ERROR (0x05). Consolidated error response for all request types.
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct RequestError {
165    pub request_id: VarInt,
166    pub error_code: VarInt,
167    pub reason_phrase: Vec<u8>,
168}
169
170// ============================================================
171// Subscribe Messages
172// ============================================================
173
174/// SUBSCRIBE (0x03). Simplified: fields moved to parameters.
175#[derive(Debug, Clone, PartialEq, Eq)]
176pub struct Subscribe {
177    pub request_id: VarInt,
178    pub track_namespace: TrackNamespace,
179    pub track_name: Vec<u8>,
180    pub parameters: Vec<KeyValuePair>,
181}
182
183/// SUBSCRIBE_OK (0x04). Simplified: most fields moved to parameters.
184#[derive(Debug, Clone, PartialEq, Eq)]
185pub struct SubscribeOk {
186    pub request_id: VarInt,
187    pub track_alias: VarInt,
188    pub parameters: Vec<KeyValuePair>,
189}
190
191/// SUBSCRIBE_UPDATE (0x02). request_id + subscription_request_id + params.
192#[derive(Debug, Clone, PartialEq, Eq)]
193pub struct SubscribeUpdate {
194    pub request_id: VarInt,
195    pub subscription_request_id: VarInt,
196    pub parameters: Vec<KeyValuePair>,
197}
198
199#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct Unsubscribe {
201    pub request_id: VarInt,
202}
203
204// ============================================================
205// Publish Messages
206// ============================================================
207
208/// PUBLISH (0x1D). Simplified: request_id + ns + name + alias + params.
209#[derive(Debug, Clone, PartialEq, Eq)]
210pub struct Publish {
211    pub request_id: VarInt,
212    pub track_namespace: TrackNamespace,
213    pub track_name: Vec<u8>,
214    pub track_alias: VarInt,
215    pub parameters: Vec<KeyValuePair>,
216}
217
218/// PUBLISH_OK (0x1E). Simplified: request_id + params.
219#[derive(Debug, Clone, PartialEq, Eq)]
220pub struct PublishOk {
221    pub request_id: VarInt,
222    pub parameters: Vec<KeyValuePair>,
223}
224
225/// PUBLISH_DONE (0x0B). Replaces SubscribeDone.
226#[derive(Debug, Clone, PartialEq, Eq)]
227pub struct PublishDone {
228    pub request_id: VarInt,
229    pub status_code: VarInt,
230    pub stream_count: VarInt,
231    pub reason_phrase: Vec<u8>,
232}
233
234// ============================================================
235// Publish Namespace Messages (renamed from Announce)
236// ============================================================
237
238/// PUBLISH_NAMESPACE (0x06). request_id + namespace + params.
239#[derive(Debug, Clone, PartialEq, Eq)]
240pub struct PublishNamespace {
241    pub request_id: VarInt,
242    pub track_namespace: TrackNamespace,
243    pub parameters: Vec<KeyValuePair>,
244}
245
246/// PUBLISH_NAMESPACE_DONE (0x09). Just namespace.
247#[derive(Debug, Clone, PartialEq, Eq)]
248pub struct PublishNamespaceDone {
249    pub track_namespace: TrackNamespace,
250}
251
252/// PUBLISH_NAMESPACE_CANCEL (0x0C). namespace + error_code + reason.
253#[derive(Debug, Clone, PartialEq, Eq)]
254pub struct PublishNamespaceCancel {
255    pub track_namespace: TrackNamespace,
256    pub error_code: VarInt,
257    pub reason_phrase: Vec<u8>,
258}
259
260// ============================================================
261// Subscribe Namespace Messages
262// ============================================================
263
264#[derive(Debug, Clone, PartialEq, Eq)]
265pub struct SubscribeNamespace {
266    pub request_id: VarInt,
267    pub namespace_prefix: TrackNamespace,
268    pub parameters: Vec<KeyValuePair>,
269}
270
271/// UNSUBSCRIBE_NAMESPACE (0x14). Just request_id.
272#[derive(Debug, Clone, PartialEq, Eq)]
273pub struct UnsubscribeNamespace {
274    pub request_id: VarInt,
275}
276
277// ============================================================
278// Track Status Messages
279// ============================================================
280
281/// TRACK_STATUS (0x0D). Same structure as Subscribe.
282#[derive(Debug, Clone, PartialEq, Eq)]
283pub struct TrackStatus {
284    pub request_id: VarInt,
285    pub track_namespace: TrackNamespace,
286    pub track_name: Vec<u8>,
287    pub parameters: Vec<KeyValuePair>,
288}
289
290// ============================================================
291// Fetch Messages
292// ============================================================
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq)]
295#[repr(u64)]
296pub enum FetchType {
297    /// Standalone fetch with explicit track + range.
298    Standalone = 1,
299    /// Joining fetch using a relative group offset.
300    RelativeJoining = 2,
301    /// Joining fetch using an absolute group.
302    AbsoluteJoining = 3,
303}
304
305impl FetchType {
306    /// Map a varint value to a FetchType, returning None for unknown values.
307    pub fn from_u64(v: u64) -> Option<Self> {
308        match v {
309            1 => Some(FetchType::Standalone),
310            2 => Some(FetchType::RelativeJoining),
311            3 => Some(FetchType::AbsoluteJoining),
312            _ => None,
313        }
314    }
315}
316
317#[derive(Debug, Clone, PartialEq, Eq)]
318pub struct Fetch {
319    pub request_id: VarInt,
320    pub fetch_type: FetchType,
321    pub fetch_payload: FetchPayload,
322    pub parameters: Vec<KeyValuePair>,
323}
324
325#[derive(Debug, Clone, PartialEq, Eq)]
326pub enum FetchPayload {
327    Standalone {
328        track_namespace: TrackNamespace,
329        track_name: Vec<u8>,
330        start_group: VarInt,
331        start_object: VarInt,
332        end_group: VarInt,
333        end_object: VarInt,
334    },
335    Joining {
336        joining_request_id: VarInt,
337        joining_start: VarInt,
338    },
339}
340
341#[derive(Debug, Clone, PartialEq, Eq)]
342pub struct FetchOk {
343    pub request_id: VarInt,
344    /// Whether the end of the track has been reached.
345    ///
346    /// Held as a raw byte rather than an enum: the draft describes 1 and 0 and
347    /// says nothing about any other value, where it does call an out-of-range
348    /// Group Order or Content Exists a protocol error. Refusing a 2 here would
349    /// be this codec's rule and not the draft's.
350    pub end_of_track: u8,
351    pub end_group: VarInt,
352    pub end_object: VarInt,
353    pub parameters: Vec<KeyValuePair>,
354}
355
356#[derive(Debug, Clone, PartialEq, Eq)]
357pub struct FetchCancel {
358    pub request_id: VarInt,
359}
360
361// ============================================================
362// Unified Message Enum
363// ============================================================
364
365/// Take one byte, or report the end of the buffer instead of panicking.
366fn read_u8(buf: &mut impl Buf) -> Result<u8, CodecError> {
367    if !buf.has_remaining() {
368        return Err(CodecError::UnexpectedEnd);
369    }
370    Ok(buf.get_u8())
371}
372
373#[derive(Debug, Clone, PartialEq, Eq)]
374pub enum ControlMessage {
375    ClientSetup(ClientSetup),
376    ServerSetup(ServerSetup),
377    GoAway(GoAway),
378    MaxRequestId(MaxRequestId),
379    RequestsBlocked(RequestsBlocked),
380    RequestOk(RequestOk),
381    RequestError(RequestError),
382    Subscribe(Subscribe),
383    SubscribeOk(SubscribeOk),
384    SubscribeUpdate(SubscribeUpdate),
385    Unsubscribe(Unsubscribe),
386    Publish(Publish),
387    PublishOk(PublishOk),
388    PublishDone(PublishDone),
389    PublishNamespace(PublishNamespace),
390    PublishNamespaceDone(PublishNamespaceDone),
391    PublishNamespaceCancel(PublishNamespaceCancel),
392    SubscribeNamespace(SubscribeNamespace),
393    UnsubscribeNamespace(UnsubscribeNamespace),
394    TrackStatus(TrackStatus),
395    Fetch(Fetch),
396    FetchOk(FetchOk),
397    FetchCancel(FetchCancel),
398}
399
400fn check_full_track_name(namespace: &TrackNamespace, track_name: &[u8]) -> Result<(), CodecError> {
401    let total = namespace.field_bytes_len().saturating_add(track_name.len());
402    if total > MAX_FULL_TRACK_NAME_LENGTH {
403        return Err(CodecError::TrackNameTooLong);
404    }
405    Ok(())
406}
407
408/// Read a Reason Phrase, holding it to the cap this draft states for a receiver.
409///
410/// "The reason phrase length has a maximum value of 1024 bytes. If an endpoint
411/// receives a length exceeding the maximum, it MUST close the session with a
412/// PROTOCOL_VIOLATION". The sentence is about what an endpoint receives, and
413/// receiving was the direction the cap was not applied to: the encoders refused
414/// an over-long phrase and the decoders accepted one.
415fn read_reason_phrase(buf: &mut impl Buf) -> Result<Vec<u8>, CodecError> {
416    let len = VarInt::decode(buf)?.into_inner() as usize;
417    if len > MAX_REASON_PHRASE_LENGTH {
418        return Err(CodecError::ReasonPhraseTooLong);
419    }
420    read_bytes(buf, len)
421}
422
423/// Refuse a FETCH whose range ends before it starts.
424///
425/// Section 9.16.3: "Fetch specifies an inclusive range of Objects starting at
426/// Start Location and ending at End Location. End Location MUST specify the
427/// same or a larger Location than Start Location for Standalone and Absolute Joining Fetches." A Joining Fetch names
428/// no explicit range - it is computed from the subscription it joins - so only
429/// a standalone range is checked here.
430///
431/// SUBSCRIBE is not checked here. Its filter moved into the parameters on
432/// this draft, and this codec carries a parameter value as the bytes it
433/// arrived as, so the start and end are not fields this function can see.
434///
435/// Applied on both sides. A range that ends before it starts selects nothing,
436/// and the peer's only recourse is an error response or a session close, so
437/// writing one is not a way to ask for anything.
438fn check_ranges(message: &ControlMessage) -> Result<(), CodecError> {
439    match message {
440        ControlMessage::Fetch(m) => match &m.fetch_payload {
441            FetchPayload::Standalone {
442                start_group, start_object, end_group, end_object, ..
443            } => check_location_range(
444                start_group.into_inner(),
445                start_object.into_inner(),
446                end_group.into_inner(),
447                end_object.into_inner(),
448            ),
449            FetchPayload::Joining { .. } => Ok(()),
450        },
451        _ => Ok(()),
452    }
453}
454
455/// Refuse a message whose discriminator disagrees with the fields beside it.
456///
457/// A discriminator is a field that says which of the fields after it are on the
458/// wire. Where this codec holds the alternatives as an enum or an `Option`
459/// beside the discriminator, a value can say one thing in the discriminator and
460/// another in the body, and the two sides of the codec resolve that
461/// disagreement differently: the encoder writes whatever the body holds, and
462/// the decoder reads whatever the discriminator announces. The result is a
463/// message that does not survive its own round trip, and the encoder is the
464/// side that can still refuse it.
465///
466/// Draft-15 has exactly one such message, which is why this is shorter than the
467/// same check on draft-14. Section 9.16 gives FETCH a Fetch Type — "There are
468/// three types of Fetch messages... An endpoint that receives a Fetch Type other
469/// than 0x1, 0x2 or 0x3 MUST close the session with a PROTOCOL_VIOLATION" — and
470/// Section 9.16.3 puts the Standalone and Joining bodies in the message as
471/// alternatives that the type selects between.
472///
473/// The messages that carried the other discriminators on draft-14 no longer do.
474/// SUBSCRIBE's Filter Type became the SUBSCRIPTION_FILTER parameter of Section
475/// 9.2.1.7, and SUBSCRIBE_OK's Content Exists became the LARGEST_OBJECT
476/// parameter of Section 9.2.1.9; a parameter is present or it is absent, so
477/// neither leaves a discriminator to disagree with. Copying draft-14's arms over
478/// unchanged would not compile, and adding fields to make them compile would
479/// invent a rule this draft does not have.
480///
481/// A mis-stated FETCH is the concrete case. A Standalone type beside a Joining
482/// body writes a request id and a start where the peer reads a Track Namespace
483/// and a Track Name, and the fetch that arrives names a track after two
484/// integers — or, more often, fails to parse, which at least is honest.
485fn check_discriminators(message: &ControlMessage) -> Result<(), CodecError> {
486    if let ControlMessage::Fetch(m) = message {
487        let body_is_standalone = matches!(m.fetch_payload, FetchPayload::Standalone { .. });
488        if body_is_standalone != (m.fetch_type == FetchType::Standalone) {
489            return Err(CodecError::InvalidField);
490        }
491    }
492    Ok(())
493}
494
495/// The one parameter type whose own definition lets it repeat.
496///
497/// Section 9.2.1.1: "The AUTHORIZATION TOKEN parameter MAY be repeated within a
498/// message as long as the combination of Token Type and Token Value are unique
499/// after resolving any aliases." That is the "unless the parameter definition
500/// explicitly allows multiple instances" carve-out of Section 9.2, and on this
501/// draft it is the only one — none of the other eleven version-specific
502/// parameters, nor any of the six setup parameters, says the like.
503///
504/// The trailing condition is not enforced here. Resolving an alias needs the
505/// session's token cache, which a codec framing one message does not have;
506/// uniqueness of the resolved pair is a session rule and not a wire rule. What
507/// is enforced is the permission itself, which is what a duplicate check needs
508/// to know.
509///
510/// The same code point, 0x03, in both namespaces: Section 9.2.1.1 assigns it to
511/// the message parameter and Section 9.3.1.5 defines the setup parameter as "See
512/// Section 9.2.1.1", so a sender may repeat it in a SETUP as well. The name is
513/// the same on draft-14, whose Section 9.2.1.1 states the permission in the
514/// shorter form; the earlier name, AUTHORIZATION INFO, belongs to drafts 07
515/// through 10, which stated no permission at all.
516const REPEATABLE_PARAMETER: u64 = 0x03;
517
518/// Every version-specific parameter type draft-15 names, from the registry of
519/// Section 13.2, Table 10.
520///
521/// DELIVERY_TIMEOUT (0x02), AUTHORIZATION_TOKEN (0x03), MAX_CACHE_DURATION
522/// (0x04), EXPIRES (0x08), LARGEST_OBJECT (0x09), PUBLISHER_PRIORITY (0x0E),
523/// FORWARD (0x10), SUBSCRIBER_PRIORITY (0x20), SUBSCRIPTION_FILTER (0x21),
524/// GROUP_ORDER (0x22), DYNAMIC_GROUPS (0x30) and NEW_GROUP_REQUEST (0x32).
525/// Four times the length of draft-14's list, because draft-15 is the draft that
526/// moved SUBSCRIBE's and SUBSCRIBE_OK's fixed fields into parameters.
527///
528/// The list exists for one rule and one direction. Section 9.2: "Receivers MUST
529/// allow duplicates of unknown parameters." A receiver may therefore refuse a
530/// repeat only of a type it can name, and a type outside this list belongs to an
531/// extension this codec has no business closing a session over. Nothing else
532/// reads it — an unknown parameter is still decoded and carried.
533const KNOWN_VERSION_SPECIFIC_PARAMETERS: &[u64] =
534    &[0x02, 0x03, 0x04, 0x08, 0x09, 0x0E, 0x10, 0x20, 0x21, 0x22, 0x30, 0x32];
535
536/// Every setup parameter type draft-15 names, from Section 9.3.1.
537///
538/// PATH (0x01), MAX_REQUEST_ID (0x02), AUTHORIZATION TOKEN (0x03),
539/// MAX_AUTH_TOKEN_CACHE_SIZE (0x04), AUTHORITY (0x05) and MOQT_IMPLEMENTATION
540/// (0x07). The last is what draft-14 numbered 0x05, colliding with AUTHORITY;
541/// draft-15 is where it moved.
542///
543/// Setup parameters are a separate namespace — Section 9.2.1 says so outright:
544/// "since Setup parameters use a separate namespace, it is impossible for these
545/// parameters to appear in Setup messages" — so a receiver deciding whether it
546/// can name a type has to know which of the two lists to consult. Reading a
547/// SETUP against the version-specific list would tolerate a repeated PATH, which
548/// this draft names and a receiver may refuse.
549const KNOWN_SETUP_PARAMETERS: &[u64] = &[0x01, 0x02, 0x03, 0x04, 0x05, 0x07];
550
551/// Refuse a parameter list a sender may not put on the wire.
552///
553/// Section 9.2: "Senders MUST NOT repeat the same parameter type in a message
554/// unless the parameter definition explicitly allows multiple instances of that
555/// type to be sent in a single message."
556///
557/// The sender's half names no exception for types the sender does not
558/// recognise, so every repeat is refused here except
559/// [`REPEATABLE_PARAMETER`]. A caller holding a parameter this codec has never
560/// heard of still may not send it twice: it knows the type it is sending, and
561/// the rule is about that knowledge, not this codec's.
562fn check_no_duplicate_parameters_sent(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
563    for (i, parameter) in parameters.iter().enumerate() {
564        let key = parameter.key.into_inner();
565        if key == REPEATABLE_PARAMETER {
566            continue;
567        }
568        if parameters[..i].iter().any(|earlier| earlier.key == parameter.key) {
569            return Err(CodecError::DuplicateParameter(key));
570        }
571    }
572    Ok(())
573}
574
575/// Refuse a received parameter list that repeats a type this draft names.
576///
577/// The receiver's half of the same sentence is narrower, and deliberately so.
578/// Section 9.2: "Receivers SHOULD check that there are no unauthorized duplicate
579/// parameters and close the session as a PROTOCOL_VIOLATION if found. Receivers
580/// MUST allow duplicates of unknown parameters."
581///
582/// So a repeat of a type in `known` is refused, and a repeat of any other type
583/// is carried. Mirroring the sender's check here instead would close sessions
584/// over frames a conforming peer is entitled to send — an extension parameter
585/// this codec does not know may legitimately repeat, and its own definition, not
586/// this one, says whether it may.
587///
588/// Code that scans a parameter list for a key takes whichever copy it meets
589/// first, so one frame carrying two values for one named type is read
590/// differently by two conforming implementations. That is what the refusal is
591/// for, and it is also why it stops at the types whose meaning is fixed here.
592fn check_no_duplicate_parameters_received(
593    parameters: &[KeyValuePair],
594    known: &[u64],
595) -> Result<(), CodecError> {
596    for (i, parameter) in parameters.iter().enumerate() {
597        let key = parameter.key.into_inner();
598        if key == REPEATABLE_PARAMETER || !known.contains(&key) {
599            continue;
600        }
601        if parameters[..i].iter().any(|earlier| earlier.key == parameter.key) {
602            return Err(CodecError::DuplicateParameter(key));
603        }
604    }
605    Ok(())
606}
607
608/// Hold every AUTHORIZATION TOKEN parameter to the Token structure it names.
609///
610/// Section 9.2.1.1: "If the Token structure cannot be decoded, the receiver
611/// MUST close the Session with KEY_VALUE_FORMATTING_ERROR." That is the answer
612/// Section 1.4.2 gives for any Type whose value does not match the
613/// serialization that Type defines; the Token is the one structure this draft
614/// spells out, and the only parameter value in it that is more than opaque
615/// bytes.
616///
617/// Both namespaces carry the type on this draft, and both reach here.
618///
619/// A type this draft cannot name is left alone. The rule is conditional on the
620/// receiver understanding the Type, and an extension's parameter carries bytes
621/// no rule here describes.
622fn check_authorization_tokens(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
623    for parameter in parameters {
624        let key = parameter.key.into_inner();
625        if key != AUTH_TOKEN_PARAMETER {
626            continue;
627        }
628        match &parameter.value {
629            KvpValue::Bytes(value) => {
630                AuthorizationToken::decode(key, value)?;
631            }
632            // Unreachable from the decoder, which picks the shape from the
633            // type and finds this one length-prefixed. A caller that built the
634            // pair in memory can still get here, and it is the same rule: the
635            // value is not the serialization the type defines.
636            KvpValue::Varint(_) => {
637                return Err(CodecError::KeyValueFormatting {
638                    key,
639                    detail: "its value is a bare varint where the type defines a Token structure",
640                });
641            }
642        }
643    }
644    Ok(())
645}
646
647/// Whether `value` is inside the range draft-15 allows for a version-specific
648/// parameter type that restricts one.
649///
650/// Four types do. FORWARD, Section 9.2.1.10: "The allowed values are 0 (don't
651/// forward) or 1 (forward). If an endpoint receives a value outside this range,
652/// it MUST close the session with PROTOCOL_VIOLATION." GROUP_ORDER, Section
653/// 9.2.1.6, says the same of Ascending (0x1) and Descending (0x2).
654/// SUBSCRIBER_PRIORITY, Section 9.2.1.5: "The range is restricted to 0-255. If a
655/// publisher receives a value outside this range, it MUST close the session with
656/// PROTOCOL_VIOLATION." DYNAMIC_GROUPS, Section 9.2.1.11: "Values larger than 1
657/// are a Protocol Violation."
658///
659/// Group Order is the one to read twice. Where drafts 07 through 14 carried it
660/// as a message field and let a request send 0x0 to mean "no preference", the
661/// parameter form has no such value: a subscriber with no preference omits the
662/// parameter, and 0x0 closes the session in every message that carries it. The
663/// asymmetry that governs the field form does not survive into this one.
664///
665/// PUBLISHER_PRIORITY (0x0E) is deliberately absent. Section 9.2.1.4 says "The
666/// value is from 0 to 255 and lower numbers get higher priority", points at
667/// Section 7 for the ordering itself, and adds "Priorities above 255 are
668/// invalid." — and stops, where each of the four above names a consequence in
669/// the next clause. Adding it here would close sessions on a sentence the draft
670/// did not write.
671fn parameter_value_in_range(key: u64, value: u64) -> bool {
672    match key {
673        // FORWARD (0x10) and DYNAMIC_GROUPS (0x30)
674        0x10 | 0x30 => value <= 1,
675        // SUBSCRIBER_PRIORITY (0x20)
676        0x20 => value <= 255,
677        // GROUP_ORDER (0x22)
678        0x22 => value == 1 || value == 2,
679        _ => true,
680    }
681}
682
683/// Refuse a parameter whose value falls outside the range its type allows.
684///
685/// Only the varint-valued shape is examined. Every type with a range is an even
686/// number, and draft-15 gives an even type a bare varint value, so a
687/// length-prefixed value under one of these keys is already a
688/// [`CodecError::KeyValueFormatting`] before it reaches here.
689fn check_parameter_value_ranges(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
690    for parameter in parameters {
691        if let KvpValue::Varint(value) = &parameter.value {
692            let key = parameter.key.into_inner();
693            let value = value.into_inner();
694            if !parameter_value_in_range(key, value) {
695                return Err(CodecError::ParameterValueOutOfRange { key, value });
696            }
697        }
698    }
699    Ok(())
700}
701
702/// Hold every SUBSCRIPTION_FILTER parameter to the filter structure it names.
703///
704/// Two sentences meet on this value. Section 5.1.2: "An endpoint that receives a
705/// filter type other than the above MUST close the session with
706/// PROTOCOL_VIOLATION." Section 9.2.1.7: "It is a length-prefixed Subscription
707/// Filter... If the length of the Subscription Filter does not match the
708/// parameter length, the publisher MUST close the session with
709/// PROTOCOL_VIOLATION."
710///
711/// Draft-14 read the same three values as fields of SUBSCRIBE and checked them
712/// there. This draft moved them inside a parameter, and a parameter whose value
713/// is a run of bytes carries a Filter Type nothing reads: the rule went from
714/// enforced to invisible without a word of either draft changing.
715///
716/// The filter is decoded and discarded. What is kept is the refusal — the value
717/// stays on the parameter as the bytes that arrived, so a caller reads it
718/// through [`SubscriptionFilter::decode`] when it wants the filter rather than
719/// the frame.
720///
721/// Version-specific parameters only. Section 9.2.1 keeps the two namespaces
722/// apart, and a setup 0x21 is not this parameter.
723fn check_subscription_filters(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
724    for parameter in parameters {
725        if parameter.key.into_inner() != SUBSCRIPTION_FILTER_PARAMETER {
726            continue;
727        }
728        match &parameter.value {
729            KvpValue::Bytes(value) => {
730                SubscriptionFilter::decode(value)?;
731            }
732            // Unreachable from the decoder: 0x21 is odd, and Section 1.4.2
733            // gives an odd Type a length-prefixed value. A caller that built
734            // the pair in memory can still get here, and it is the same rule.
735            KvpValue::Varint(_) => {
736                return Err(CodecError::SubscriptionFilterMalformed {
737                    detail: "its value is a bare varint where the type defines a filter",
738                });
739            }
740        }
741    }
742    Ok(())
743}
744
745/// Decode a version-specific parameter list, refusing a repeated known type.
746fn decode_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
747    let parameters = KeyValuePair::decode_list(buf)?;
748    check_no_duplicate_parameters_received(&parameters, KNOWN_VERSION_SPECIFIC_PARAMETERS)?;
749    check_authorization_tokens(&parameters)?;
750    check_parameter_value_ranges(&parameters)?;
751    check_subscription_filters(&parameters)?;
752    Ok(parameters)
753}
754
755/// Decode a SETUP message's parameter list, refusing a repeated known type.
756///
757/// Separate from [`decode_parameters`] only in which list of names it consults;
758/// see [`KNOWN_SETUP_PARAMETERS`] for why the two cannot share one.
759fn decode_setup_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
760    let parameters = KeyValuePair::decode_list(buf)?;
761    check_no_duplicate_parameters_received(&parameters, KNOWN_SETUP_PARAMETERS)?;
762    check_authorization_tokens(&parameters)?;
763    Ok(parameters)
764}
765
766/// Encode a version-specific parameter list, refusing every list
767/// [`decode_parameters`] would refuse.
768///
769/// The duplicate rule the sender is held to is its own — it exempts a parameter
770/// type rather than a namespace, and the exempt type has the same code point in
771/// each, which is why one call covers both. The three value rules are the
772/// reader's, applied here for the reason each of them states a close: a value
773/// that is not what its Type defines is one the receiver must close the session
774/// over, so writing it is not a way to send it. The sender's first sign of
775/// trouble would be the session going.
776fn encode_parameters(parameters: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
777    check_no_duplicate_parameters_sent(parameters)?;
778    check_authorization_tokens(parameters)?;
779    check_parameter_value_ranges(parameters)?;
780    check_subscription_filters(parameters)?;
781    KeyValuePair::encode_list_checked(parameters, buf)?;
782    Ok(())
783}
784
785/// Encode a SETUP message's parameter list.
786///
787/// Separate from [`encode_parameters`] for the reason the decode side is: two of
788/// the three value rules are version-specific, and a setup 0x21 or 0x22 is not
789/// the parameter either of them describes. The token is in both namespaces and
790/// is held to its structure in both.
791fn encode_setup_parameters(
792    parameters: &[KeyValuePair],
793    buf: &mut impl BufMut,
794) -> Result<(), CodecError> {
795    check_no_duplicate_parameters_sent(parameters)?;
796    check_authorization_tokens(parameters)?;
797    KeyValuePair::encode_list_checked(parameters, buf)?;
798    Ok(())
799}
800
801impl ControlMessage {
802    pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
803        check_discriminators(self)?;
804        check_ranges(self)?;
805        let mut payload = Vec::with_capacity(256);
806        self.encode_payload(&mut payload)?;
807
808        if payload.len() > MAX_MESSAGE_LENGTH {
809            return Err(CodecError::MessageTooLong(payload.len()));
810        }
811
812        let msg_type = self.message_type();
813        VarInt::from_usize(msg_type.id() as usize).encode(buf);
814        // Draft-15: 16-bit length (big-endian)
815        buf.put_u16(payload.len() as u16);
816        buf.put_slice(&payload);
817        Ok(())
818    }
819
820    pub fn decode(buf: &mut impl Buf) -> Result<Self, CodecError> {
821        let type_id = VarInt::decode(buf)?.into_inner();
822        let msg_type =
823            MessageType::from_id(type_id).ok_or(CodecError::UnknownMessageType(type_id))?;
824        // Draft-15: 16-bit length (big-endian)
825        if buf.remaining() < 2 {
826            return Err(CodecError::UnexpectedEnd);
827        }
828        let payload_len = buf.get_u16() as usize;
829        if buf.remaining() < payload_len {
830            return Err(CodecError::UnexpectedEnd);
831        }
832        let payload_bytes = buf.copy_to_bytes(payload_len);
833        let mut payload = &payload_bytes[..];
834        let msg = match Self::decode_payload(msg_type, &mut payload) {
835            Ok(msg) => msg,
836            // The fields wanted more bytes than the Length allowed. This buffer
837            // is already bounded by that Length, so running out inside it cannot
838            // mean the message is still arriving - which is what the same error
839            // means everywhere else, and why a reader loops on it rather than
840            // closing. Here there is nothing left to arrive.
841            Err(
842                CodecError::UnexpectedEnd
843                | CodecError::Kvp(crate::kvp::KvpError::UnexpectedEnd)
844                | CodecError::Kvp(crate::kvp::KvpError::VarInt(
845                    crate::varint::VarIntError::UnexpectedEnd,
846                ))
847                | CodecError::VarInt(crate::varint::VarIntError::UnexpectedEnd),
848            ) => {
849                return Err(CodecError::ControlMessageLengthMismatch {
850                    declared: payload_len,
851                    detail: "its fields ran past the end",
852                });
853            }
854            Err(e) => return Err(e),
855        };
856        check_ranges(&msg)?;
857        // Draft-15 Section 9: "The length is set to the number of bytes in
858        // Message Payload... If the length does not match the length of the
859        // Message Payload, the receiver MUST close the session with a
860        // PROTOCOL_VIOLATION."
861        //
862        // A payload longer than its fields is the half that reads as success:
863        // the declared length keeps the outer stream in sync, so bytes no field
864        // consumed are simply dropped and nothing downstream notices. That hides
865        // a real framing disagreement — a peer emitting a field this codec does
866        // not know about looks identical to a peer sending nothing extra.
867        if payload.has_remaining() {
868            return Err(CodecError::ControlMessageLengthMismatch {
869                declared: payload_len,
870                detail: "its fields left bytes unread",
871            });
872        }
873        Ok(msg)
874    }
875
876    fn encode_payload(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
877        match self {
878            ControlMessage::ClientSetup(m) => {
879                encode_setup_parameters(&m.parameters, buf)?;
880            }
881            ControlMessage::ServerSetup(m) => {
882                encode_setup_parameters(&m.parameters, buf)?;
883            }
884            ControlMessage::GoAway(m) => {
885                if m.new_session_uri.len() > MAX_GOAWAY_URI_LENGTH {
886                    return Err(CodecError::GoAwayUriTooLong);
887                }
888                VarInt::from_usize(m.new_session_uri.len()).encode(buf);
889                buf.put_slice(&m.new_session_uri);
890            }
891            ControlMessage::MaxRequestId(m) => {
892                m.request_id.encode(buf);
893            }
894            ControlMessage::RequestsBlocked(m) => {
895                m.maximum_request_id.encode(buf);
896            }
897            ControlMessage::RequestOk(m) => {
898                m.request_id.encode(buf);
899                encode_parameters(&m.parameters, buf)?;
900            }
901            ControlMessage::RequestError(m) => {
902                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
903                    return Err(CodecError::ReasonPhraseTooLong);
904                }
905                m.request_id.encode(buf);
906                m.error_code.encode(buf);
907                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
908                buf.put_slice(&m.reason_phrase);
909            }
910            ControlMessage::Subscribe(m) => {
911                m.request_id.encode(buf);
912                m.track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
913                m.track_namespace.encode(buf);
914                check_full_track_name(&m.track_namespace, &m.track_name)?;
915                VarInt::from_usize(m.track_name.len()).encode(buf);
916                buf.put_slice(&m.track_name);
917                encode_parameters(&m.parameters, buf)?;
918            }
919            ControlMessage::SubscribeOk(m) => {
920                m.request_id.encode(buf);
921                m.track_alias.encode(buf);
922                encode_parameters(&m.parameters, buf)?;
923            }
924            ControlMessage::SubscribeUpdate(m) => {
925                m.request_id.encode(buf);
926                m.subscription_request_id.encode(buf);
927                encode_parameters(&m.parameters, buf)?;
928            }
929            ControlMessage::Unsubscribe(m) => {
930                m.request_id.encode(buf);
931            }
932            ControlMessage::Publish(m) => {
933                m.request_id.encode(buf);
934                m.track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
935                m.track_namespace.encode(buf);
936                check_full_track_name(&m.track_namespace, &m.track_name)?;
937                VarInt::from_usize(m.track_name.len()).encode(buf);
938                buf.put_slice(&m.track_name);
939                m.track_alias.encode(buf);
940                encode_parameters(&m.parameters, buf)?;
941            }
942            ControlMessage::PublishOk(m) => {
943                m.request_id.encode(buf);
944                encode_parameters(&m.parameters, buf)?;
945            }
946            ControlMessage::PublishDone(m) => {
947                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
948                    return Err(CodecError::ReasonPhraseTooLong);
949                }
950                m.request_id.encode(buf);
951                m.status_code.encode(buf);
952                m.stream_count.encode(buf);
953                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
954                buf.put_slice(&m.reason_phrase);
955            }
956            ControlMessage::PublishNamespace(m) => {
957                m.request_id.encode(buf);
958                m.track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
959                m.track_namespace.encode(buf);
960                encode_parameters(&m.parameters, buf)?;
961            }
962            ControlMessage::PublishNamespaceDone(m) => {
963                m.track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
964                m.track_namespace.encode(buf);
965            }
966            ControlMessage::PublishNamespaceCancel(m) => {
967                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
968                    return Err(CodecError::ReasonPhraseTooLong);
969                }
970                m.track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
971                m.track_namespace.encode(buf);
972                m.error_code.encode(buf);
973                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
974                buf.put_slice(&m.reason_phrase);
975            }
976            ControlMessage::SubscribeNamespace(m) => {
977                m.request_id.encode(buf);
978                m.namespace_prefix.validate(TrackNamespaceRules::for_draft(15))?;
979                m.namespace_prefix.encode(buf);
980                encode_parameters(&m.parameters, buf)?;
981            }
982            ControlMessage::UnsubscribeNamespace(m) => {
983                m.request_id.encode(buf);
984            }
985            ControlMessage::TrackStatus(m) => {
986                m.request_id.encode(buf);
987                m.track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
988                m.track_namespace.encode(buf);
989                check_full_track_name(&m.track_namespace, &m.track_name)?;
990                VarInt::from_usize(m.track_name.len()).encode(buf);
991                buf.put_slice(&m.track_name);
992                encode_parameters(&m.parameters, buf)?;
993            }
994            ControlMessage::Fetch(m) => {
995                m.request_id.encode(buf);
996                VarInt::from_usize(m.fetch_type as usize).encode(buf);
997                match &m.fetch_payload {
998                    FetchPayload::Standalone {
999                        track_namespace,
1000                        track_name,
1001                        start_group,
1002                        start_object,
1003                        end_group,
1004                        end_object,
1005                    } => {
1006                        track_namespace.validate(TrackNamespaceRules::for_draft(15))?;
1007                        track_namespace.encode(buf);
1008                        check_full_track_name(track_namespace, track_name)?;
1009                        VarInt::from_usize(track_name.len()).encode(buf);
1010                        buf.put_slice(track_name);
1011                        start_group.encode(buf);
1012                        start_object.encode(buf);
1013                        end_group.encode(buf);
1014                        end_object.encode(buf);
1015                    }
1016                    FetchPayload::Joining { joining_request_id, joining_start } => {
1017                        joining_request_id.encode(buf);
1018                        joining_start.encode(buf);
1019                    }
1020                }
1021                encode_parameters(&m.parameters, buf)?;
1022            }
1023            ControlMessage::FetchOk(m) => {
1024                m.request_id.encode(buf);
1025                buf.put_u8(m.end_of_track);
1026                m.end_group.encode(buf);
1027                m.end_object.encode(buf);
1028                encode_parameters(&m.parameters, buf)?;
1029            }
1030            ControlMessage::FetchCancel(m) => {
1031                m.request_id.encode(buf);
1032            }
1033        }
1034        Ok(())
1035    }
1036
1037    fn decode_payload(msg_type: MessageType, buf: &mut impl Buf) -> Result<Self, CodecError> {
1038        match msg_type {
1039            MessageType::ClientSetup => {
1040                let parameters = decode_setup_parameters(buf)?;
1041                Ok(ControlMessage::ClientSetup(ClientSetup { parameters }))
1042            }
1043            MessageType::ServerSetup => {
1044                let parameters = decode_setup_parameters(buf)?;
1045                Ok(ControlMessage::ServerSetup(ServerSetup { parameters }))
1046            }
1047            MessageType::GoAway => {
1048                let uri_len = VarInt::decode(buf)?.into_inner() as usize;
1049                if uri_len > MAX_GOAWAY_URI_LENGTH {
1050                    return Err(CodecError::GoAwayUriTooLong);
1051                }
1052                let uri = read_bytes(buf, uri_len)?;
1053                Ok(ControlMessage::GoAway(GoAway { new_session_uri: uri }))
1054            }
1055            MessageType::MaxRequestId => {
1056                let request_id = VarInt::decode(buf)?;
1057                Ok(ControlMessage::MaxRequestId(MaxRequestId { request_id }))
1058            }
1059            MessageType::RequestsBlocked => {
1060                let maximum_request_id = VarInt::decode(buf)?;
1061                Ok(ControlMessage::RequestsBlocked(RequestsBlocked { maximum_request_id }))
1062            }
1063            MessageType::RequestOk => {
1064                let request_id = VarInt::decode(buf)?;
1065                let parameters = decode_parameters(buf)?;
1066                Ok(ControlMessage::RequestOk(RequestOk { request_id, parameters }))
1067            }
1068            MessageType::RequestError => {
1069                let request_id = VarInt::decode(buf)?;
1070                let error_code = VarInt::decode(buf)?;
1071                let reason_phrase = read_reason_phrase(buf)?;
1072                Ok(ControlMessage::RequestError(RequestError {
1073                    request_id,
1074                    error_code,
1075                    reason_phrase,
1076                }))
1077            }
1078            MessageType::Subscribe => {
1079                let request_id = VarInt::decode(buf)?;
1080                let track_namespace = TrackNamespace::decode(buf)?;
1081                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1082                let track_name = read_bytes(buf, track_name_len)?;
1083                check_full_track_name(&track_namespace, &track_name)?;
1084                let parameters = decode_parameters(buf)?;
1085                Ok(ControlMessage::Subscribe(Subscribe {
1086                    request_id,
1087                    track_namespace,
1088                    track_name,
1089                    parameters,
1090                }))
1091            }
1092            MessageType::SubscribeOk => {
1093                let request_id = VarInt::decode(buf)?;
1094                let track_alias = VarInt::decode(buf)?;
1095                let parameters = decode_parameters(buf)?;
1096                Ok(ControlMessage::SubscribeOk(SubscribeOk { request_id, track_alias, parameters }))
1097            }
1098            MessageType::SubscribeUpdate => {
1099                let request_id = VarInt::decode(buf)?;
1100                let subscription_request_id = VarInt::decode(buf)?;
1101                let parameters = decode_parameters(buf)?;
1102                Ok(ControlMessage::SubscribeUpdate(SubscribeUpdate {
1103                    request_id,
1104                    subscription_request_id,
1105                    parameters,
1106                }))
1107            }
1108            MessageType::Unsubscribe => {
1109                let request_id = VarInt::decode(buf)?;
1110                Ok(ControlMessage::Unsubscribe(Unsubscribe { request_id }))
1111            }
1112            MessageType::Publish => {
1113                let request_id = VarInt::decode(buf)?;
1114                let track_namespace = TrackNamespace::decode(buf)?;
1115                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1116                let track_name = read_bytes(buf, track_name_len)?;
1117                check_full_track_name(&track_namespace, &track_name)?;
1118                let track_alias = VarInt::decode(buf)?;
1119                let parameters = decode_parameters(buf)?;
1120                Ok(ControlMessage::Publish(Publish {
1121                    request_id,
1122                    track_namespace,
1123                    track_name,
1124                    track_alias,
1125                    parameters,
1126                }))
1127            }
1128            MessageType::PublishOk => {
1129                let request_id = VarInt::decode(buf)?;
1130                let parameters = decode_parameters(buf)?;
1131                Ok(ControlMessage::PublishOk(PublishOk { request_id, parameters }))
1132            }
1133            MessageType::PublishDone => {
1134                let request_id = VarInt::decode(buf)?;
1135                let status_code = VarInt::decode(buf)?;
1136                let stream_count = VarInt::decode(buf)?;
1137                let reason_phrase = read_reason_phrase(buf)?;
1138                Ok(ControlMessage::PublishDone(PublishDone {
1139                    request_id,
1140                    status_code,
1141                    stream_count,
1142                    reason_phrase,
1143                }))
1144            }
1145            MessageType::PublishNamespace => {
1146                let request_id = VarInt::decode(buf)?;
1147                let track_namespace = TrackNamespace::decode(buf)?;
1148                let parameters = decode_parameters(buf)?;
1149                Ok(ControlMessage::PublishNamespace(PublishNamespace {
1150                    request_id,
1151                    track_namespace,
1152                    parameters,
1153                }))
1154            }
1155            MessageType::PublishNamespaceDone => {
1156                let track_namespace = TrackNamespace::decode(buf)?;
1157                Ok(ControlMessage::PublishNamespaceDone(PublishNamespaceDone { track_namespace }))
1158            }
1159            MessageType::PublishNamespaceCancel => {
1160                let track_namespace = TrackNamespace::decode(buf)?;
1161                let error_code = VarInt::decode(buf)?;
1162                let reason_phrase = read_reason_phrase(buf)?;
1163                Ok(ControlMessage::PublishNamespaceCancel(PublishNamespaceCancel {
1164                    track_namespace,
1165                    error_code,
1166                    reason_phrase,
1167                }))
1168            }
1169            MessageType::SubscribeNamespace => {
1170                let request_id = VarInt::decode(buf)?;
1171                let namespace_prefix = TrackNamespace::decode(buf)?;
1172                let parameters = decode_parameters(buf)?;
1173                Ok(ControlMessage::SubscribeNamespace(SubscribeNamespace {
1174                    request_id,
1175                    namespace_prefix,
1176                    parameters,
1177                }))
1178            }
1179            MessageType::UnsubscribeNamespace => {
1180                let request_id = VarInt::decode(buf)?;
1181                Ok(ControlMessage::UnsubscribeNamespace(UnsubscribeNamespace { request_id }))
1182            }
1183            MessageType::TrackStatus => {
1184                let request_id = VarInt::decode(buf)?;
1185                let track_namespace = TrackNamespace::decode(buf)?;
1186                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1187                let track_name = read_bytes(buf, track_name_len)?;
1188                check_full_track_name(&track_namespace, &track_name)?;
1189                let parameters = decode_parameters(buf)?;
1190                Ok(ControlMessage::TrackStatus(TrackStatus {
1191                    request_id,
1192                    track_namespace,
1193                    track_name,
1194                    parameters,
1195                }))
1196            }
1197            MessageType::Fetch => {
1198                let request_id = VarInt::decode(buf)?;
1199                let fetch_type_val = VarInt::decode(buf)?.into_inner();
1200                let fetch_type = FetchType::from_u64(fetch_type_val)
1201                    .ok_or(CodecError::InvalidFetchType(fetch_type_val))?;
1202                let fetch_payload = match fetch_type {
1203                    FetchType::Standalone => {
1204                        let track_namespace = TrackNamespace::decode(buf)?;
1205                        let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1206                        let track_name = read_bytes(buf, track_name_len)?;
1207                        check_full_track_name(&track_namespace, &track_name)?;
1208                        let start_group = VarInt::decode(buf)?;
1209                        let start_object = VarInt::decode(buf)?;
1210                        let end_group = VarInt::decode(buf)?;
1211                        let end_object = VarInt::decode(buf)?;
1212                        FetchPayload::Standalone {
1213                            track_namespace,
1214                            track_name,
1215                            start_group,
1216                            start_object,
1217                            end_group,
1218                            end_object,
1219                        }
1220                    }
1221                    FetchType::RelativeJoining | FetchType::AbsoluteJoining => {
1222                        let joining_request_id = VarInt::decode(buf)?;
1223                        let joining_start = VarInt::decode(buf)?;
1224                        FetchPayload::Joining { joining_request_id, joining_start }
1225                    }
1226                };
1227                let parameters = decode_parameters(buf)?;
1228                Ok(ControlMessage::Fetch(Fetch {
1229                    request_id,
1230                    fetch_type,
1231                    fetch_payload,
1232                    parameters,
1233                }))
1234            }
1235            MessageType::FetchOk => {
1236                let request_id = VarInt::decode(buf)?;
1237                let end_of_track = read_u8(buf)?;
1238                let end_group = VarInt::decode(buf)?;
1239                let end_object = VarInt::decode(buf)?;
1240                let parameters = decode_parameters(buf)?;
1241                Ok(ControlMessage::FetchOk(FetchOk {
1242                    request_id,
1243                    end_of_track,
1244                    end_group,
1245                    end_object,
1246                    parameters,
1247                }))
1248            }
1249            MessageType::FetchCancel => {
1250                let request_id = VarInt::decode(buf)?;
1251                Ok(ControlMessage::FetchCancel(FetchCancel { request_id }))
1252            }
1253        }
1254    }
1255
1256    pub fn message_type(&self) -> MessageType {
1257        match self {
1258            ControlMessage::ClientSetup(_) => MessageType::ClientSetup,
1259            ControlMessage::ServerSetup(_) => MessageType::ServerSetup,
1260            ControlMessage::GoAway(_) => MessageType::GoAway,
1261            ControlMessage::MaxRequestId(_) => MessageType::MaxRequestId,
1262            ControlMessage::RequestsBlocked(_) => MessageType::RequestsBlocked,
1263            ControlMessage::RequestOk(_) => MessageType::RequestOk,
1264            ControlMessage::RequestError(_) => MessageType::RequestError,
1265            ControlMessage::Subscribe(_) => MessageType::Subscribe,
1266            ControlMessage::SubscribeOk(_) => MessageType::SubscribeOk,
1267            ControlMessage::SubscribeUpdate(_) => MessageType::SubscribeUpdate,
1268            ControlMessage::Unsubscribe(_) => MessageType::Unsubscribe,
1269            ControlMessage::Publish(_) => MessageType::Publish,
1270            ControlMessage::PublishOk(_) => MessageType::PublishOk,
1271            ControlMessage::PublishDone(_) => MessageType::PublishDone,
1272            ControlMessage::PublishNamespace(_) => MessageType::PublishNamespace,
1273            ControlMessage::PublishNamespaceDone(_) => MessageType::PublishNamespaceDone,
1274            ControlMessage::PublishNamespaceCancel(_) => MessageType::PublishNamespaceCancel,
1275            ControlMessage::SubscribeNamespace(_) => MessageType::SubscribeNamespace,
1276            ControlMessage::UnsubscribeNamespace(_) => MessageType::UnsubscribeNamespace,
1277            ControlMessage::TrackStatus(_) => MessageType::TrackStatus,
1278            ControlMessage::Fetch(_) => MessageType::Fetch,
1279            ControlMessage::FetchOk(_) => MessageType::FetchOk,
1280            ControlMessage::FetchCancel(_) => MessageType::FetchCancel,
1281        }
1282    }
1283}