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