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