Skip to main content

moqtap_codec/draft16/
message.rs

1//! Draft-16 control message encoding and decoding.
2//!
3//! Key changes from draft-15:
4//! - SubscribeUpdate → RequestUpdate, field renamed to existing_request_id
5//! - New: Namespace (0x08), NamespaceDone (0x0e) — namespace_suffix only
6//! - Removed: UnsubscribeNamespace (0x14)
7//! - RequestError gains retry_interval field
8//! - SubscribeNamespace gains subscribe_options varint
9//! - PublishNamespaceDone simplifies to just request_id
10//! - Framing: type_id(vi) + payload_length(16) + payload (same as draft-15)
11
12use crate::auth_token::{AuthorizationToken, AUTH_TOKEN_PARAMETER};
13use crate::error::{
14    CodecError, MAX_FULL_TRACK_NAME_LENGTH, MAX_GOAWAY_URI_LENGTH, MAX_MESSAGE_LENGTH,
15    MAX_REASON_PHRASE_LENGTH,
16};
17use crate::kvp::{KeyValuePair, KvpError, KvpValue, MAX_KVP_VALUE_LEN};
18use crate::subscription_filter::{SubscriptionFilter, SUBSCRIPTION_FILTER_PARAMETER};
19pub use crate::types::check_location_range;
20use crate::types::*;
21use crate::varint::VarInt;
22use bytes::{Buf, BufMut};
23
24// ============================================================
25// Key-Value-Pair Type delta encoding
26// ============================================================
27//
28// Draft-16 Section 1.4.2: "Key-Value-Pairs encode a Type value as a delta from
29// the previous Type value, or from 0 if there is no previous Type value."
30//
31// This is the wire shape for every Key-Value-Pair on this draft, and it arrived
32// with draft-16 — drafts 15 and earlier write the Type absolutely. Draft-16
33// Appendix A.1 records the change as "Delta encode Key-Value-Pairs for
34// Parameters and Headers". Both users of the shape in this module are covered:
35// the count-prefixed Parameters list carried by most control messages, and the
36// Track Extensions run that fills the tail of SUBSCRIBE_OK, PUBLISH and
37// FETCH_OK.
38//
39// The delta resets to 0 at the start of each run, so a message carrying both a
40// Parameters list and a Track Extensions run restarts the count between them.
41//
42// Only the Type is delta-encoded. The value still follows the even/odd rule of
43// Section 1.4.2 — "Length: Only present when Type is odd" — and it is the
44// resolved Type that decides, not the delta that encoded it.
45//
46// Object Extension Headers in the data plane are Key-Value-Pairs too, but this
47// codec carries that block as opaque bytes and never resolves a Type inside it,
48// so it needs no change here.
49
50/// Resolve a delta-encoded Type against the Type before it.
51///
52/// Draft-16 Section 1.4.2: "The previous Type value plus the Delta Type MUST NOT
53/// be greater than 2^64 - 1. If a Delta Type is received that would be too
54/// large, the Session MUST be closed with a PROTOCOL_VIOLATION." Deltas
55/// accumulate, so a peer sending a handful of near-maximum deltas can drive the
56/// running sum past the end; without the checked add a debug build panics on the
57/// addition and a release build wraps and reports the pair under a Type its
58/// sender never wrote.
59///
60/// A resolved Type also has to be a Type this draft can express. Draft-16 writes
61/// every field as a varint, which tops out below the 2^64 - 1 the sentence
62/// names, so a sum landing above the varint maximum is refused here as well: it
63/// has no draft-16 wire form, and admitting one would produce a pair this codec
64/// could decode but never write back.
65fn add_delta(prev_key: u64, delta: u64) -> Result<VarInt, CodecError> {
66    prev_key
67        .checked_add(delta)
68        .and_then(|sum| VarInt::from_u64(sum).ok())
69        .ok_or(CodecError::KeyDeltaOverflow(prev_key, delta))
70}
71
72/// Read one Key-Value-Pair, resolving its Type against `prev_key` and advancing
73/// `prev_key` to the resolved value.
74fn decode_kvp_delta_pair(
75    prev_key: &mut u64,
76    buf: &mut impl Buf,
77) -> Result<KeyValuePair, CodecError> {
78    let delta = VarInt::decode(buf)?.into_inner();
79    let key = add_delta(*prev_key, delta)?;
80    let abs_key = key.into_inner();
81    *prev_key = abs_key;
82
83    let value = if abs_key.is_multiple_of(2) {
84        KvpValue::Varint(VarInt::decode(buf)?)
85    } else {
86        let len = VarInt::decode(buf)?.into_inner() as usize;
87        // Section 1.4.2: "The maximum length of a value is 2^16-1 bytes. If an
88        // endpoint receives a length larger than the maximum, it MUST close the
89        // session with a PROTOCOL_VIOLATION." `KeyValuePair::decode` applied
90        // this before the Type became a delta, and dropping it here would trade
91        // one defect for another.
92        if len > MAX_KVP_VALUE_LEN {
93            return Err(KvpError::ValueTooLong(len).into());
94        }
95        KvpValue::Bytes(read_bytes(buf, len)?)
96    };
97
98    Ok(KeyValuePair { key, value })
99}
100
101/// Write one Key-Value-Pair, encoding its Type as a delta from `prev_key` and
102/// advancing `prev_key` to this pair's Type.
103///
104/// Refuses a Type below the one before it. The delta is an unsigned difference,
105/// so a descending pair wraps the subtraction into a nine-byte delta that the
106/// peer resolves to an unrelated Type — the codec would put a frame on the wire
107/// that its own decoder reads as something else entirely.
108fn encode_kvp_delta_pair(
109    prev_key: &mut u64,
110    pair: &KeyValuePair,
111    buf: &mut impl BufMut,
112) -> Result<(), CodecError> {
113    let abs_key = pair.key.into_inner();
114    let delta = abs_key
115        .checked_sub(*prev_key)
116        .ok_or(CodecError::ParametersOutOfOrder(*prev_key, abs_key))?;
117    *prev_key = abs_key;
118    // Both operands are valid varints and `delta` is their difference, so it is
119    // in range by construction; the `?` is the type system's, not a rule's.
120    VarInt::from_u64(delta)?.encode(buf);
121
122    match &pair.value {
123        KvpValue::Varint(v) => v.encode(buf),
124        KvpValue::Bytes(bytes) => {
125            if bytes.len() > MAX_KVP_VALUE_LEN {
126                return Err(KvpError::ValueTooLong(bytes.len()).into());
127            }
128            VarInt::from_usize(bytes.len()).encode(buf);
129            buf.put_slice(bytes);
130        }
131    }
132    Ok(())
133}
134
135/// Immutable Extensions, Extension Header Type 0xB.
136///
137/// Section 11.2: "The Immutable Extensions (Extension Header Type 0xB) contains
138/// a sequence of Key-Value-Pairs (see Figure 2) which are also Track or Object
139/// Extension Headers." The Type is odd, so its value is length-prefixed bytes,
140/// and those bytes are another delta-typed run starting from 0.
141const IMMUTABLE_EXTENSIONS: u64 = 0x0B;
142
143/// Whether `value` is inside the range draft-16 allows for an extension header
144/// type that restricts one.
145///
146/// Three types do, each in Section 11 and each answering anything outside its
147/// range with a session close.
148///
149/// DELIVERY_TIMEOUT (0x02), Section 11.1: "DELIVERY_TIMEOUT, if present, MUST
150/// contain a value greater than 0. If an endpoint receives a DELIVERY_TIMEOUT
151/// equal to 0 it MUST close the session with PROTOCOL_VIOLATION." Draft-16 is
152/// the only draft that states this. Draft-17 renamed the type to
153/// OBJECT_DELIVERY_TIMEOUT and gives it no range at all.
154///
155/// DEFAULT_PUBLISHER_GROUP_ORDER (0x22), Section 11.1.1.2: "The allowed values
156/// are Ascending (0x1) or Descending (0x2). If an endpoint receives a value
157/// outside this range, it MUST close the session with PROTOCOL_VIOLATION."
158///
159/// DYNAMIC_GROUPS (0x30), Section 11.1.1.3: "The allowed values are 0 or 1... If
160/// an endpoint receives a value larger than 1, it MUST close the session with
161/// PROTOCOL_VIOLATION." Draft-15 carried this as a Message Parameter, where it
162/// is [`parameter_value_in_range`]'s business; draft-16 moved it to this
163/// namespace, and the two registries number their entries independently.
164///
165/// DEFAULT_PUBLISHER_PRIORITY (0x0E) is not here. Section 11.1.1.1 says
166/// "Priorities above 255 are invalid" and stops, where the three above name a
167/// consequence in the next clause. A range stated without one is not a close.
168fn track_extension_value_in_range(key: u64, value: u64) -> bool {
169    match key {
170        // DELIVERY_TIMEOUT (0x02)
171        0x02 => value > 0,
172        // DEFAULT_PUBLISHER_GROUP_ORDER (0x22)
173        0x22 => value == 1 || value == 2,
174        // DYNAMIC_GROUPS (0x30)
175        0x30 => value <= 1,
176        _ => true,
177    }
178}
179
180/// Refuse a Track Extension whose value falls outside the range its type allows,
181/// wherever in the run it is carried.
182///
183/// Extension headers only. The Message Parameter registry is a separate
184/// namespace that gives the same numbers to different types — 0x22 is
185/// GROUP_ORDER there and DEFAULT_PUBLISHER_GROUP_ORDER here — so the two lists
186/// are checked against their own tables and neither table is consulted for the
187/// other's types.
188///
189/// # Inside Immutable Extensions as well as beside them
190///
191/// The run is walked one level down through Immutable Extensions, whose contents
192/// Section 11.2 defines as extension headers themselves. A rule applied only to
193/// the outer run is a rule a peer opts out of by moving one pair inside the
194/// block, and the block is not an obscure corner: it is where an Original
195/// Publisher puts anything a relay must not rewrite, which is exactly where a
196/// track's group order and dynamic-group support belong.
197///
198/// Bytes under 0xB that do not parse as a Key-Value-Pair run are left alone
199/// rather than refused. Section 11.2 answers that with "A Track is considered
200/// malformed", which Section 2.4.2 does not make a session close, and turning
201/// it into one here would end sessions over a rule the draft answers otherwise.
202/// A nested block that does parse is checked; one that does not is carried, and
203/// the caller still has the bytes.
204fn check_track_extension_values(extensions: &[KeyValuePair]) -> Result<(), CodecError> {
205    for extension in extensions {
206        let key = extension.key.into_inner();
207        match &extension.value {
208            KvpValue::Varint(value) => {
209                let value = value.into_inner();
210                if !track_extension_value_in_range(key, value) {
211                    return Err(CodecError::TrackPropertyValueOutOfRange { key, value });
212                }
213            }
214            KvpValue::Bytes(bytes) if key == IMMUTABLE_EXTENSIONS => {
215                let mut inner = &bytes[..];
216                let mut prev_key: u64 = 0;
217                let mut nested = Vec::new();
218                let mut readable = true;
219                while inner.has_remaining() {
220                    match decode_kvp_delta_pair(&mut prev_key, &mut inner) {
221                        Ok(pair) => nested.push(pair),
222                        // Not a Key-Value-Pair run. See the note above: this is
223                        // a malformed Track and not a session close.
224                        //
225                        // `break` rather than ending the walk: Section 11.2's
226                        // rule ("A Track is considered malformed ... A
227                        // Key-Value-Pair cannot be parsed") is about the block
228                        // whose pairs will not parse, and says nothing about
229                        // its neighbours. Ending the walk would let a peer keep
230                        // an out-of-range extension from being looked at by
231                        // putting an unparseable block in front of it.
232                        Err(_) => {
233                            readable = false;
234                            break;
235                        }
236                    }
237                }
238                // The pairs read before the failure are not checked either. A
239                // run that stops mid-pair was being read under framing it does
240                // not have, so the numbers ahead of the break are not reliably
241                // the types and values they look like — and refusing on one
242                // would close a session over a misparse. The whole block is
243                // carried, which is what the note above promises.
244                if readable {
245                    check_track_extension_values(&nested)?;
246                }
247            }
248            KvpValue::Bytes(_) => {}
249        }
250    }
251    Ok(())
252}
253
254/// Decode any remaining bytes in `buf` as a run of delta-typed KVPs until `buf`
255/// is empty. Used for draft-16 `track_extensions`, which has no explicit
256/// count — extensions simply fill the rest of the control-message payload.
257fn decode_track_extensions(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
258    let mut out = Vec::new();
259    let mut prev_key: u64 = 0;
260    while buf.has_remaining() {
261        out.push(decode_kvp_delta_pair(&mut prev_key, buf)?);
262    }
263    check_track_extension_values(&out)?;
264    Ok(out)
265}
266
267/// Encode `track_extensions` (each KVP back-to-back, no count prefix), with
268/// Types delta-encoded from 0.
269///
270/// Held to the same value ranges as the decoder. A value this codec refuses to
271/// read is one it must not write: the peer that receives it is required to close
272/// the session, so the sender's first sign of trouble would be the session
273/// going.
274fn encode_track_extensions(exts: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
275    check_track_extension_values(exts)?;
276    let mut prev_key: u64 = 0;
277    for kvp in exts {
278        encode_kvp_delta_pair(&mut prev_key, kvp, buf)?;
279    }
280    Ok(())
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq)]
284#[repr(u64)]
285pub enum MessageType {
286    RequestUpdate = 0x02,
287    Subscribe = 0x03,
288    SubscribeOk = 0x04,
289    RequestError = 0x05,
290    PublishNamespace = 0x06,
291    RequestOk = 0x07,
292    Namespace = 0x08,
293    PublishNamespaceDone = 0x09,
294    Unsubscribe = 0x0A,
295    PublishDone = 0x0B,
296    PublishNamespaceCancel = 0x0C,
297    TrackStatus = 0x0D,
298    NamespaceDone = 0x0E,
299    GoAway = 0x10,
300    SubscribeNamespace = 0x11,
301    MaxRequestId = 0x15,
302    Fetch = 0x16,
303    FetchCancel = 0x17,
304    FetchOk = 0x18,
305    RequestsBlocked = 0x1A,
306    Publish = 0x1D,
307    PublishOk = 0x1E,
308    ClientSetup = 0x20,
309    ServerSetup = 0x21,
310}
311
312impl MessageType {
313    pub fn from_id(id: u64) -> Option<Self> {
314        match id {
315            0x02 => Some(MessageType::RequestUpdate),
316            0x03 => Some(MessageType::Subscribe),
317            0x04 => Some(MessageType::SubscribeOk),
318            0x05 => Some(MessageType::RequestError),
319            0x06 => Some(MessageType::PublishNamespace),
320            0x07 => Some(MessageType::RequestOk),
321            0x08 => Some(MessageType::Namespace),
322            0x09 => Some(MessageType::PublishNamespaceDone),
323            0x0A => Some(MessageType::Unsubscribe),
324            0x0B => Some(MessageType::PublishDone),
325            0x0C => Some(MessageType::PublishNamespaceCancel),
326            0x0D => Some(MessageType::TrackStatus),
327            0x0E => Some(MessageType::NamespaceDone),
328            0x10 => Some(MessageType::GoAway),
329            0x11 => Some(MessageType::SubscribeNamespace),
330            0x15 => Some(MessageType::MaxRequestId),
331            0x16 => Some(MessageType::Fetch),
332            0x17 => Some(MessageType::FetchCancel),
333            0x18 => Some(MessageType::FetchOk),
334            0x1A => Some(MessageType::RequestsBlocked),
335            0x1D => Some(MessageType::Publish),
336            0x1E => Some(MessageType::PublishOk),
337            0x20 => Some(MessageType::ClientSetup),
338            0x21 => Some(MessageType::ServerSetup),
339            _ => None,
340        }
341    }
342
343    pub fn id(&self) -> u64 {
344        *self as u64
345    }
346
347    /// This type's name in the shared vector corpus: the `message_type` its
348    /// draft's `codec/messages/*.json` files carry, in `snake_case`.
349    pub fn name(&self) -> &'static str {
350        match self {
351            MessageType::RequestUpdate => "request_update",
352            MessageType::Subscribe => "subscribe",
353            MessageType::SubscribeOk => "subscribe_ok",
354            MessageType::RequestError => "request_error",
355            MessageType::PublishNamespace => "publish_namespace",
356            MessageType::RequestOk => "request_ok",
357            MessageType::Namespace => "namespace",
358            MessageType::PublishNamespaceDone => "publish_namespace_done",
359            MessageType::Unsubscribe => "unsubscribe",
360            MessageType::PublishDone => "publish_done",
361            MessageType::PublishNamespaceCancel => "publish_namespace_cancel",
362            MessageType::TrackStatus => "track_status",
363            MessageType::NamespaceDone => "namespace_done",
364            MessageType::GoAway => "goaway",
365            MessageType::SubscribeNamespace => "subscribe_namespace",
366            MessageType::MaxRequestId => "max_request_id",
367            MessageType::Fetch => "fetch",
368            MessageType::FetchCancel => "fetch_cancel",
369            MessageType::FetchOk => "fetch_ok",
370            MessageType::RequestsBlocked => "requests_blocked",
371            MessageType::Publish => "publish",
372            MessageType::PublishOk => "publish_ok",
373            MessageType::ClientSetup => "client_setup",
374            MessageType::ServerSetup => "server_setup",
375        }
376    }
377}
378
379// ============================================================
380// Session Lifecycle Messages
381// ============================================================
382
383#[derive(Debug, Clone, PartialEq, Eq)]
384pub struct ClientSetup {
385    pub parameters: Vec<KeyValuePair>,
386}
387
388#[derive(Debug, Clone, PartialEq, Eq)]
389pub struct ServerSetup {
390    pub parameters: Vec<KeyValuePair>,
391}
392
393#[derive(Debug, Clone, PartialEq, Eq)]
394pub struct GoAway {
395    pub new_session_uri: Vec<u8>,
396}
397
398#[derive(Debug, Clone, PartialEq, Eq)]
399pub struct MaxRequestId {
400    pub request_id: VarInt,
401}
402
403#[derive(Debug, Clone, PartialEq, Eq)]
404pub struct RequestsBlocked {
405    pub maximum_request_id: VarInt,
406}
407
408// ============================================================
409// Consolidated Response Messages
410// ============================================================
411
412#[derive(Debug, Clone, PartialEq, Eq)]
413pub struct RequestOk {
414    pub request_id: VarInt,
415    pub parameters: Vec<KeyValuePair>,
416}
417
418/// REQUEST_ERROR (0x05). Draft-16 adds retry_interval field.
419#[derive(Debug, Clone, PartialEq, Eq)]
420pub struct RequestError {
421    pub request_id: VarInt,
422    pub error_code: VarInt,
423    pub retry_interval: VarInt,
424    pub reason_phrase: Vec<u8>,
425}
426
427// ============================================================
428// Subscribe Messages
429// ============================================================
430
431#[derive(Debug, Clone, PartialEq, Eq)]
432pub struct Subscribe {
433    pub request_id: VarInt,
434    pub track_namespace: TrackNamespace,
435    pub track_name: Vec<u8>,
436    pub parameters: Vec<KeyValuePair>,
437}
438
439#[derive(Debug, Clone, PartialEq, Eq)]
440pub struct SubscribeOk {
441    pub request_id: VarInt,
442    pub track_alias: VarInt,
443    pub parameters: Vec<KeyValuePair>,
444    /// Track extensions: KVPs that follow `parameters` and continue until
445    /// the end of the control-message payload. Empty if none.
446    pub track_extensions: Vec<KeyValuePair>,
447}
448
449/// REQUEST_UPDATE (0x02). Drafts 15 and earlier name this codepoint
450/// SUBSCRIBE_UPDATE.
451#[derive(Debug, Clone, PartialEq, Eq)]
452pub struct RequestUpdate {
453    pub request_id: VarInt,
454    pub existing_request_id: VarInt,
455    pub parameters: Vec<KeyValuePair>,
456}
457
458#[derive(Debug, Clone, PartialEq, Eq)]
459pub struct Unsubscribe {
460    pub request_id: VarInt,
461}
462
463// ============================================================
464// Publish Messages
465// ============================================================
466
467#[derive(Debug, Clone, PartialEq, Eq)]
468pub struct Publish {
469    pub request_id: VarInt,
470    pub track_namespace: TrackNamespace,
471    pub track_name: Vec<u8>,
472    pub track_alias: VarInt,
473    pub parameters: Vec<KeyValuePair>,
474    /// Track extensions: KVPs that follow `parameters` and continue until
475    /// the end of the control-message payload. Empty if none.
476    pub track_extensions: Vec<KeyValuePair>,
477}
478
479#[derive(Debug, Clone, PartialEq, Eq)]
480pub struct PublishOk {
481    pub request_id: VarInt,
482    pub parameters: Vec<KeyValuePair>,
483}
484
485#[derive(Debug, Clone, PartialEq, Eq)]
486pub struct PublishDone {
487    pub request_id: VarInt,
488    pub status_code: VarInt,
489    pub stream_count: VarInt,
490    pub reason_phrase: Vec<u8>,
491}
492
493// ============================================================
494// Publish Namespace Messages
495// ============================================================
496
497#[derive(Debug, Clone, PartialEq, Eq)]
498pub struct PublishNamespace {
499    pub request_id: VarInt,
500    pub track_namespace: TrackNamespace,
501    pub parameters: Vec<KeyValuePair>,
502}
503
504/// PUBLISH_NAMESPACE_DONE (0x09). Draft-16 carries just request_id; draft-15
505/// carries the track namespace instead.
506#[derive(Debug, Clone, PartialEq, Eq)]
507pub struct PublishNamespaceDone {
508    pub request_id: VarInt,
509}
510
511/// PUBLISH_NAMESPACE_CANCEL (0x0C). Draft-16: request_id + error_code + reason.
512#[derive(Debug, Clone, PartialEq, Eq)]
513pub struct PublishNamespaceCancel {
514    pub request_id: VarInt,
515    pub error_code: VarInt,
516    pub reason_phrase: Vec<u8>,
517}
518
519// ============================================================
520// Namespace Messages (new in draft-16)
521// ============================================================
522
523/// NAMESPACE (0x08). Carries namespace_suffix.
524#[derive(Debug, Clone, PartialEq, Eq)]
525pub struct Namespace {
526    pub namespace_suffix: TrackNamespace,
527}
528
529/// NAMESPACE_DONE (0x0E). Carries namespace_suffix.
530#[derive(Debug, Clone, PartialEq, Eq)]
531pub struct NamespaceDone {
532    pub namespace_suffix: TrackNamespace,
533}
534
535// ============================================================
536// Subscribe Namespace Messages
537// ============================================================
538
539/// SUBSCRIBE_NAMESPACE (0x11). Draft-16: gains subscribe_options varint.
540#[derive(Debug, Clone, PartialEq, Eq)]
541pub struct SubscribeNamespace {
542    pub request_id: VarInt,
543    pub namespace_prefix: TrackNamespace,
544    pub subscribe_options: VarInt,
545    pub parameters: Vec<KeyValuePair>,
546}
547
548// ============================================================
549// Track Status Messages
550// ============================================================
551
552#[derive(Debug, Clone, PartialEq, Eq)]
553pub struct TrackStatus {
554    pub request_id: VarInt,
555    pub track_namespace: TrackNamespace,
556    pub track_name: Vec<u8>,
557    pub parameters: Vec<KeyValuePair>,
558}
559
560// ============================================================
561// Fetch Messages
562// ============================================================
563
564#[derive(Debug, Clone, Copy, PartialEq, Eq)]
565#[repr(u64)]
566pub enum FetchType {
567    /// Standalone fetch with explicit track + range.
568    Standalone = 1,
569    /// Joining fetch using a relative group offset.
570    RelativeJoining = 2,
571    /// Joining fetch using an absolute group.
572    AbsoluteJoining = 3,
573}
574
575impl FetchType {
576    /// Map a varint value to a FetchType, returning None for unknown values.
577    pub fn from_u64(v: u64) -> Option<Self> {
578        match v {
579            1 => Some(FetchType::Standalone),
580            2 => Some(FetchType::RelativeJoining),
581            3 => Some(FetchType::AbsoluteJoining),
582            _ => None,
583        }
584    }
585}
586
587#[derive(Debug, Clone, PartialEq, Eq)]
588pub struct Fetch {
589    pub request_id: VarInt,
590    pub fetch_type: FetchType,
591    pub fetch_payload: FetchPayload,
592    pub parameters: Vec<KeyValuePair>,
593}
594
595#[derive(Debug, Clone, PartialEq, Eq)]
596pub enum FetchPayload {
597    Standalone {
598        track_namespace: TrackNamespace,
599        track_name: Vec<u8>,
600        start_group: VarInt,
601        start_object: VarInt,
602        end_group: VarInt,
603        end_object: VarInt,
604    },
605    Joining {
606        joining_request_id: VarInt,
607        joining_start: VarInt,
608    },
609}
610
611#[derive(Debug, Clone, PartialEq, Eq)]
612pub struct FetchOk {
613    pub request_id: VarInt,
614    /// Whether the end of the track has been reached.
615    ///
616    /// Held as a raw byte rather than an enum: the draft describes 1 and 0 and
617    /// says nothing about any other value, where it does call an out-of-range
618    /// Group Order or Content Exists a protocol error. Refusing a 2 here would
619    /// be this codec's rule and not the draft's.
620    pub end_of_track: u8,
621    pub end_group: VarInt,
622    pub end_object: VarInt,
623    pub parameters: Vec<KeyValuePair>,
624    /// Track extensions: KVPs that follow `parameters` and continue until
625    /// the end of the control-message payload. Empty if none.
626    pub track_extensions: Vec<KeyValuePair>,
627}
628
629#[derive(Debug, Clone, PartialEq, Eq)]
630pub struct FetchCancel {
631    pub request_id: VarInt,
632}
633
634// ============================================================
635// Unified Message Enum
636// ============================================================
637
638/// Take one byte, or report the end of the buffer instead of panicking.
639fn read_u8(buf: &mut impl Buf) -> Result<u8, CodecError> {
640    if !buf.has_remaining() {
641        return Err(CodecError::UnexpectedEnd);
642    }
643    Ok(buf.get_u8())
644}
645
646#[derive(Debug, Clone, PartialEq, Eq)]
647pub enum ControlMessage {
648    ClientSetup(ClientSetup),
649    ServerSetup(ServerSetup),
650    GoAway(GoAway),
651    MaxRequestId(MaxRequestId),
652    RequestsBlocked(RequestsBlocked),
653    RequestOk(RequestOk),
654    RequestError(RequestError),
655    Subscribe(Subscribe),
656    SubscribeOk(SubscribeOk),
657    RequestUpdate(RequestUpdate),
658    Unsubscribe(Unsubscribe),
659    Publish(Publish),
660    PublishOk(PublishOk),
661    PublishDone(PublishDone),
662    PublishNamespace(PublishNamespace),
663    PublishNamespaceDone(PublishNamespaceDone),
664    PublishNamespaceCancel(PublishNamespaceCancel),
665    Namespace(Namespace),
666    NamespaceDone(NamespaceDone),
667    SubscribeNamespace(SubscribeNamespace),
668    TrackStatus(TrackStatus),
669    Fetch(Fetch),
670    FetchOk(FetchOk),
671    FetchCancel(FetchCancel),
672}
673
674fn check_full_track_name(namespace: &TrackNamespace, track_name: &[u8]) -> Result<(), CodecError> {
675    let total = namespace.field_bytes_len().saturating_add(track_name.len());
676    if total > MAX_FULL_TRACK_NAME_LENGTH {
677        return Err(CodecError::TrackNameTooLong);
678    }
679    Ok(())
680}
681
682/// Read a Reason Phrase, holding it to the cap this draft states for a receiver.
683///
684/// "The reason phrase length has a maximum value of 1024 bytes. If an endpoint
685/// receives a length exceeding the maximum, it MUST close the session with a
686/// PROTOCOL_VIOLATION". The sentence is about what an endpoint receives, and
687/// receiving was the direction the cap was not applied to: the encoders refused
688/// an over-long phrase and the decoders accepted one.
689fn read_reason_phrase(buf: &mut impl Buf) -> Result<Vec<u8>, CodecError> {
690    let len = VarInt::decode(buf)?.into_inner() as usize;
691    if len > MAX_REASON_PHRASE_LENGTH {
692        return Err(CodecError::ReasonPhraseTooLong);
693    }
694    read_bytes(buf, len)
695}
696
697/// Refuse a FETCH whose range ends before it starts.
698///
699/// Section 9.16.3: "Fetch specifies an inclusive range of Objects starting at
700/// Start Location and ending at End Location. End Location MUST specify the
701/// same or a larger Location than Start Location for Standalone and Absolute Joining Fetches." A Joining Fetch names
702/// no explicit range - it is computed from the subscription it joins - so only
703/// a standalone range is checked here.
704///
705/// SUBSCRIBE is not checked here. Its filter moved into the parameters on
706/// this draft, and this codec carries a parameter value as the bytes it
707/// arrived as, so the start and end are not fields this function can see.
708///
709/// Applied on both sides. A range that ends before it starts selects nothing,
710/// and the peer's only recourse is an error response or a session close, so
711/// writing one is not a way to ask for anything.
712fn check_ranges(message: &ControlMessage) -> Result<(), CodecError> {
713    match message {
714        ControlMessage::Fetch(m) => match &m.fetch_payload {
715            FetchPayload::Standalone {
716                start_group, start_object, end_group, end_object, ..
717            } => check_location_range(
718                start_group.into_inner(),
719                start_object.into_inner(),
720                end_group.into_inner(),
721                end_object.into_inner(),
722            ),
723            FetchPayload::Joining { .. } => Ok(()),
724        },
725        _ => Ok(()),
726    }
727}
728
729/// Refuse a message whose discriminator disagrees with the fields beside it.
730///
731/// A discriminator is a field that says which of the fields after it are on the
732/// wire. This codec holds the alternatives in an enum, so a value can say one
733/// thing in its discriminator and another in its body, and the two sides of the
734/// codec resolve that differently: the encoder writes whatever the body holds,
735/// and the decoder reads whatever the discriminator announces.
736///
737/// The result is a message that does not survive its own round trip. A FETCH
738/// whose Fetch Type says Standalone and whose body is a joining pair encodes to
739/// a request id and a start where a namespace and a name belong, and comes back
740/// as a Standalone fetch of a track named after two integers — or, more often,
741/// as an error, which at least is honest. Refusing at the encoder keeps the two
742/// readings from ever diverging on the wire.
743///
744/// FETCH is the only message on draft-16 with such a field. Drafts 07 through 14
745/// have three: SUBSCRIBE's Filter Type and SUBSCRIBE_OK's ContentExists are the
746/// other two, and both are gone from draft-16 — the filter moved into the
747/// parameters as SUBSCRIPTION_FILTER, and SUBSCRIBE_OK's optional largest
748/// location left with it.
749fn check_discriminators(message: &ControlMessage) -> Result<(), CodecError> {
750    if let ControlMessage::Fetch(m) = message {
751        let body_is_standalone = matches!(m.fetch_payload, FetchPayload::Standalone { .. });
752        if body_is_standalone != (m.fetch_type == FetchType::Standalone) {
753            return Err(CodecError::InvalidField);
754        }
755    }
756    Ok(())
757}
758
759// ============================================================
760// Duplicate Parameter Types
761// ============================================================
762//
763// Draft-16 Section 9.2 states the rule in three sentences, and they do not say
764// the same thing to the two sides:
765//
766//   "Senders MUST NOT repeat the same parameter type in a message unless the
767//   parameter definition explicitly allows multiple instances of that type to
768//   be sent in a single message. Receivers SHOULD check that there are no
769//   unexpected duplicate parameters and close the session as a
770//   PROTOCOL_VIOLATION if found. Receivers MUST allow duplicates of unknown
771//   Setup Parameters."
772//
773// The sender's half names no exception for types the sender does not
774// recognise, so a caller holding a parameter this codec has never heard of
775// still may not send it twice. The receiver's half has the opposite shape: the
776// last sentence is a MUST, and it forbids closing the session over a repeat of
777// a type the receiver cannot name. So the encoder refuses more than the decoder
778// does, deliberately. Making the two symmetric breaks one rule whichever way it
779// is done — a wide decoder closes sessions the draft says to keep open, and a
780// narrow encoder emits repeats the draft says never to write.
781//
782// Both halves work on resolved Types rather than the deltas that encoded them,
783// so a repeat is found the same way it always was; on the wire it now shows up
784// as a delta of zero.
785
786/// The one Parameter Type draft-16 lets a message carry more than once.
787///
788/// Section 9.2.2.1: "The AUTHORIZATION TOKEN parameter MAY be repeated within a
789/// message as long as the combination of Token Type and Token Value are unique
790/// after resolving any aliases." That is the "unless the parameter definition
791/// explicitly allows multiple instances" carve-out of Section 9.2, and on
792/// draft-16 it is the only one. The same number is the AUTHORIZATION TOKEN
793/// Setup Parameter in Section 9.3.1.5, which describes itself as "funcionally
794/// equivalient to the AUTHORIZATION TOKEN message parameter" and lets an
795/// endpoint "specify one or more tokens", so the exemption holds in both
796/// namespaces.
797///
798/// Uniqueness "after resolving any aliases" needs a session's token cache, which
799/// a codec does not have. So repeats of this type are carried in both
800/// directions and the caller decides.
801const AUTHORIZATION_TOKEN: u64 = 0x03;
802
803/// The Setup Parameter types draft-16 defines, from the definitions in Section
804/// 9.3.1: PATH (0x01), MAX_REQUEST_ID (0x02), AUTHORIZATION TOKEN (0x03),
805/// MAX_AUTH_TOKEN_CACHE_SIZE (0x04), AUTHORITY (0x05) and MOQT_IMPLEMENTATION
806/// (0x07).
807///
808/// The list exists for one rule and one direction: "Receivers MUST allow
809/// duplicates of unknown Setup Parameters." A type outside this list is one an
810/// extension defined, and this codec has no business closing a session over it.
811/// Nothing else reads the list — an unknown Setup Parameter is still decoded and
812/// carried, as "Receivers ignore unrecognized Setup Parameters" requires.
813const KNOWN_SETUP_PARAMETERS: &[u64] = &[0x01, 0x02, 0x03, 0x04, 0x05, 0x07];
814
815/// The Message Parameter types draft-16 defines, from the registry in Section
816/// 13.2: DELIVERY_TIMEOUT (0x02), AUTHORIZATION_TOKEN (0x03), EXPIRES (0x08),
817/// LARGEST_OBJECT (0x09), FORWARD (0x10), SUBSCRIBER_PRIORITY (0x20),
818/// SUBSCRIPTION_FILTER (0x21), GROUP_ORDER (0x22) and NEW_GROUP_REQUEST (0x32).
819///
820/// Setup Parameters and Message Parameters are separate namespaces — Section
821/// 9.2: "Setup Parameters use a namespace that is constant across all MOQT
822/// versions. All other messages use a version-specific namespace" — so the two
823/// lists are kept apart rather than merged. Merging them would let a repeat of
824/// 0x01 be refused in a SUBSCRIBE, where draft-16 assigns that number to
825/// nothing at all.
826const KNOWN_MESSAGE_PARAMETERS: &[u64] = &[0x02, 0x03, 0x08, 0x09, 0x10, 0x20, 0x21, 0x22, 0x32];
827
828/// The sender's half: refuse every repeated Parameter Type but the one whose
829/// definition allows it.
830///
831/// Wider than [`check_received_duplicate_parameters`] on purpose — see the
832/// note above this function's neighbours. A repeat this codec writes is a frame
833/// nothing downstream agrees on: code that scans a parameter list for a key
834/// takes whichever copy it meets first, so one frame carrying two values for
835/// one type is read two ways by two conforming implementations. That is what
836/// makes the sender's half a MUST NOT rather than advice.
837fn check_sent_duplicate_parameters(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
838    for (i, parameter) in parameters.iter().enumerate() {
839        if parameter.key.into_inner() == AUTHORIZATION_TOKEN {
840            continue;
841        }
842        if parameters[..i].iter().any(|earlier| earlier.key == parameter.key) {
843            return Err(CodecError::DuplicateParameter(parameter.key.into_inner()));
844        }
845    }
846    Ok(())
847}
848
849/// The receiver's half: refuse a repeated Parameter Type this draft names, and
850/// carry a repeat of any other.
851///
852/// `known` is the registry for the namespace the message uses — Setup or
853/// Message. A type outside it is one "Receivers MUST allow duplicates of"
854/// covers, and refusing it would close a session over an extension this codec
855/// was never told about.
856fn check_received_duplicate_parameters(
857    parameters: &[KeyValuePair],
858    known: &[u64],
859) -> Result<(), CodecError> {
860    for (i, parameter) in parameters.iter().enumerate() {
861        let key = parameter.key.into_inner();
862        if key == AUTHORIZATION_TOKEN || !known.contains(&key) {
863            continue;
864        }
865        if parameters[..i].iter().any(|earlier| earlier.key == parameter.key) {
866            return Err(CodecError::DuplicateParameter(key));
867        }
868    }
869    Ok(())
870}
871
872/// Hold every AUTHORIZATION TOKEN parameter to the Token structure it names.
873///
874/// Section 9.2.2.1: "If the Token structure cannot be decoded, the receiver
875/// MUST close the Session with KEY_VALUE_FORMATTING_ERROR." That is the answer
876/// Section 1.4.2 gives for any Type whose value does not match the
877/// serialization that Type defines; the Token is the one structure this draft
878/// spells out, and the only parameter value in it that is more than opaque
879/// bytes.
880///
881/// Both namespaces carry the type on this draft, and both reach here.
882///
883/// A type this draft cannot name is left alone. The rule is conditional on the
884/// receiver understanding the Type, and an extension's parameter carries bytes
885/// no rule here describes.
886fn check_authorization_tokens(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
887    for parameter in parameters {
888        let key = parameter.key.into_inner();
889        if key != AUTH_TOKEN_PARAMETER {
890            continue;
891        }
892        match &parameter.value {
893            KvpValue::Bytes(value) => {
894                AuthorizationToken::decode(key, value)?;
895            }
896            // Unreachable from the decoder, which picks the shape from the
897            // type and finds this one length-prefixed. A caller that built the
898            // pair in memory can still get here, and it is the same rule: the
899            // value is not the serialization the type defines.
900            KvpValue::Varint(_) => {
901                return Err(CodecError::KeyValueFormatting {
902                    key,
903                    detail: "its value is a bare varint where the type defines a Token structure",
904                });
905            }
906        }
907    }
908    Ok(())
909}
910
911/// Hold every SUBSCRIPTION_FILTER parameter to the filter structure it names.
912///
913/// Two sentences meet on this value. Section 5.1.2: "An endpoint that receives a
914/// filter type other than the above MUST close the session with
915/// PROTOCOL_VIOLATION." Section 9.2.2.5: "It is a length-prefixed Subscription
916/// Filter... If the length of the Subscription Filter does not match the
917/// parameter length, the publisher MUST close the session with
918/// PROTOCOL_VIOLATION."
919///
920/// Draft-14 read the same three values as fields of SUBSCRIBE and checked them
921/// there. Draft-15 moved them inside a parameter, and a parameter whose value is
922/// a run of bytes carries a Filter Type nothing reads: the rule went from
923/// enforced to invisible without a word of either draft changing.
924///
925/// The filter is decoded and discarded. What is kept is the refusal — the value
926/// stays on the parameter as the bytes that arrived, so a caller reads it
927/// through [`SubscriptionFilter::decode`] when it wants the filter rather than
928/// the frame.
929///
930/// Message parameters only. This draft keeps the two namespaces apart, and a
931/// setup 0x21 is not this parameter.
932fn check_subscription_filters(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
933    for parameter in parameters {
934        if parameter.key.into_inner() != SUBSCRIPTION_FILTER_PARAMETER {
935            continue;
936        }
937        match &parameter.value {
938            KvpValue::Bytes(value) => {
939                SubscriptionFilter::decode(value)?;
940            }
941            // Unreachable from the decoder: 0x21 is odd, and an odd Type takes a
942            // length-prefixed value. A caller that built the pair in memory can
943            // still get here, and it is the same rule.
944            KvpValue::Varint(_) => {
945                return Err(CodecError::SubscriptionFilterMalformed {
946                    detail: "its value is a bare varint where the type defines a filter",
947                });
948            }
949        }
950    }
951    Ok(())
952}
953
954/// Refuse a Message Parameter whose type this draft does not define.
955///
956/// Section 9.2: "All Message Parameters MUST be defined in the negotiated
957/// version of MOQT or negotiated via Setup Parameters. An endpoint that receives
958/// an unknown Message Parameter MUST close the session with PROTOCOL_VIOLATION."
959///
960/// This is the one rule in the parameter paragraph that changed direction at
961/// this draft. Drafts 11 through 15 say, at draft-15 Section 9.2, "Receivers
962/// MUST allow duplicates of unknown parameters", which takes for granted that
963/// unknown parameters arrive and are carried. Draft-16 narrows that sentence to
964/// "unknown Setup Parameters" and adds this one beside it, in the same
965/// paragraph — so a type this codec cannot name is carried in a SETUP and ends
966/// the session anywhere else.
967///
968/// [`KNOWN_MESSAGE_PARAMETERS`] is what "defined in the negotiated version"
969/// means here, and it is checked against Section 13.2 rather than assembled from
970/// the types this codec happens to read. A missing entry would close sessions
971/// over parameters the draft assigns, which is the expensive way to be wrong.
972///
973/// The other half of the sentence — "or negotiated via Setup Parameters" — is
974/// not something a codec can settle. It describes an extension the two endpoints
975/// agreed on in their SETUP, and this codec implements no such extension, so
976/// every type outside the registry is unknown to it.
977fn check_message_parameters_are_known(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
978    for parameter in parameters {
979        let key = parameter.key.into_inner();
980        if !KNOWN_MESSAGE_PARAMETERS.contains(&key) {
981            return Err(CodecError::UnknownMessageParameter(key));
982        }
983    }
984    Ok(())
985}
986
987/// Whether `value` is inside the range draft-16 allows for a Message Parameter
988/// type that restricts one.
989///
990/// Four types do. FORWARD, Section 9.2.2.8: "The allowed values are 0 (don't
991/// forward) or 1 (forward). If an endpoint receives a value outside this range,
992/// it MUST close the session with PROTOCOL_VIOLATION." GROUP_ORDER, Section
993/// 9.2.2.4, says the same of Ascending (0x1) and Descending (0x2).
994/// SUBSCRIBER_PRIORITY, Section 9.2.2.3: "The range is restricted to 0-255. If a
995/// publisher receives a value outside this range, it MUST close the session with
996/// PROTOCOL_VIOLATION." DELIVERY_TIMEOUT, Section 9.2.2.2: "DELIVERY_TIMEOUT, if
997/// present, MUST contain a value greater than 0. If an endpoint receives a
998/// DELIVERY_TIMEOUT equal to 0 it MUST close the session with
999/// PROTOCOL_VIOLATION."
1000///
1001/// The fourth is stated by draft-16 alone, and stated twice — once here and once
1002/// in Section 11.1 of the extension header namespace, which
1003/// [`track_extension_value_in_range`] answers. Draft-15 has no such sentence and
1004/// draft-17 renamed the type to OBJECT_DELIVERY_TIMEOUT and dropped the range,
1005/// so this is one draft wide in both namespaces. A zero timeout is the case
1006/// worth having: it reads as "no timeout" to an implementation that treats
1007/// absence and zero alike, which is the opposite of what a timeout of zero would
1008/// mean if it were legal.
1009///
1010/// Draft-15's fourth entry, DYNAMIC_GROUPS, is not here: draft-16 moved it out
1011/// of the parameter registry and into the extension header registry as a Track
1012/// Extension, where [`track_extension_value_in_range`] holds it to the range it
1013/// states there. Draft-15's PUBLISHER_PRIORITY is gone for a different reason —
1014/// draft-16 does not define the parameter at all.
1015fn parameter_value_in_range(key: u64, value: u64) -> bool {
1016    match key {
1017        // DELIVERY_TIMEOUT (0x02)
1018        0x02 => value > 0,
1019        // FORWARD (0x10)
1020        0x10 => value <= 1,
1021        // SUBSCRIBER_PRIORITY (0x20)
1022        0x20 => value <= 255,
1023        // GROUP_ORDER (0x22)
1024        0x22 => value == 1 || value == 2,
1025        _ => true,
1026    }
1027}
1028
1029/// Refuse a Message Parameter whose value falls outside the range its type
1030/// allows.
1031///
1032/// Message Parameters only. Each rule is stated for a named Message Parameter,
1033/// and the Setup registry is a separate namespace that defines none of these
1034/// numbers, so a SETUP carrying type 0x22 is carrying something the draft has
1035/// not given a range to. Refusing it here would close the session on a reading
1036/// the draft never gives.
1037///
1038/// Only the varint-valued shape is examined. Every type with a range is an even
1039/// number, and draft-16 gives an even type a bare varint value, so a
1040/// length-prefixed value under one of these keys is already a
1041/// [`CodecError::KeyValueFormatting`] before it reaches here.
1042fn check_parameter_value_ranges(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
1043    for parameter in parameters {
1044        if let KvpValue::Varint(value) = &parameter.value {
1045            let key = parameter.key.into_inner();
1046            let value = value.into_inner();
1047            if !parameter_value_in_range(key, value) {
1048                return Err(CodecError::ParameterValueOutOfRange { key, value });
1049            }
1050        }
1051    }
1052    Ok(())
1053}
1054
1055/// Decode a count-prefixed parameter list with delta-encoded Types, refusing a
1056/// repeat of a type in `known`.
1057///
1058/// `message_namespace` says which of the two rules about unknown types applies.
1059/// The namespaces part company here and only here: an unknown Message Parameter
1060/// ends the session, and an unknown Setup Parameter is carried because "Receivers
1061/// ignore unrecognized Setup Parameters".
1062fn decode_parameters_in(
1063    buf: &mut impl Buf,
1064    known: &[u64],
1065    message_namespace: bool,
1066) -> Result<Vec<KeyValuePair>, CodecError> {
1067    let count = VarInt::decode(buf)?.into_inner() as usize;
1068    let mut parameters = crate::types::reserve_bounded(count, buf);
1069    let mut prev_key: u64 = 0;
1070    for _ in 0..count {
1071        parameters.push(decode_kvp_delta_pair(&mut prev_key, buf)?);
1072    }
1073    if message_namespace {
1074        check_message_parameters_are_known(&parameters)?;
1075        check_parameter_value_ranges(&parameters)?;
1076        check_subscription_filters(&parameters)?;
1077    }
1078    check_received_duplicate_parameters(&parameters, known)?;
1079    check_authorization_tokens(&parameters)?;
1080    Ok(parameters)
1081}
1082
1083/// Decode the Message Parameters of a control message.
1084fn decode_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
1085    decode_parameters_in(buf, KNOWN_MESSAGE_PARAMETERS, true)
1086}
1087
1088/// Decode the Setup Parameters of a CLIENT_SETUP or SERVER_SETUP.
1089fn decode_setup_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
1090    decode_parameters_in(buf, KNOWN_SETUP_PARAMETERS, false)
1091}
1092
1093/// Encode a count-prefixed parameter list with delta-encoded Types, refusing
1094/// every list [`decode_parameters_in`] would refuse *over a value*.
1095///
1096/// The duplicate rule is the sender's own and does not consult a registry, so
1097/// there is nothing for the two namespaces to disagree about there. The value
1098/// rules are the reader's, and `message_namespace` says which of them apply for
1099/// the same reason it does on the decode side: a setup 0x21 or 0x22 is not the
1100/// parameter the version-specific rules describe.
1101///
1102/// They are applied on the way out because each of them states a close. A value
1103/// that is not what its Type defines is one the receiver must close the session
1104/// over, so writing it is not a way to send it — the sender's first sign of
1105/// trouble would be the session going.
1106///
1107/// # The one rule that is decode-only, and why
1108///
1109/// [`check_message_parameters_are_known`] is not called here. That is the rule
1110/// whose sentence has a second half: Section 9.2 says "All Message Parameters MUST be defined
1111/// in the negotiated version of MOQT or negotiated via Setup Parameters", and
1112/// it is that second clause the neighbouring function's own doc says a codec
1113/// cannot settle — it describes an extension the two endpoints agreed on in
1114/// their SETUP, which this codec does not implement.
1115///
1116/// A decoder has to resolve that the conservative way. It was handed bytes, it
1117/// has no record of what the two peers negotiated, and the draft's answer to a
1118/// parameter it cannot name is a close. An encoder is in the opposite position:
1119/// its caller *is* the endpoint that negotiated, and is the only party that
1120/// knows the type was agreed. Refusing here would make a negotiated extension
1121/// unsendable through this codec — and unreplayable, which is the same argument
1122/// `data_stream.rs`'s `extensions_permitted_at` makes about a rule that
1123/// addresses the receiving endpoint: a writer that refused it could not
1124/// reproduce a capture containing one.
1125///
1126/// Draft-17 takes the same position in the same place, with a fallback arm in
1127/// its `encode_parameters` that writes an unknown Type as a plain even/odd pair
1128/// while its decoder answers `UnknownMessageParameter` for the same number.
1129/// This is a difference between the two directions, not between the drafts.
1130///
1131/// It is also a gated one rather than an accident.
1132/// `tests/unknown_message_parameter.rs`'s `an_unknown_message_parameter_is_refused`
1133/// drives exactly this asymmetry on this draft: it hands the encoder type 0x41,
1134/// requires it to be written — its `expect` says in so many words that the
1135/// encoder writes the parameters it is given — and requires the decoder to
1136/// answer `UnknownMessageParameter`. A check here would fail that test on the
1137/// line before the one it is about.
1138fn encode_parameters_in(
1139    parameters: &[KeyValuePair],
1140    buf: &mut impl BufMut,
1141    message_namespace: bool,
1142) -> Result<(), CodecError> {
1143    check_sent_duplicate_parameters(parameters)?;
1144    if message_namespace {
1145        check_parameter_value_ranges(parameters)?;
1146        check_subscription_filters(parameters)?;
1147    }
1148    check_authorization_tokens(parameters)?;
1149    VarInt::from_usize(parameters.len()).encode(buf);
1150    let mut prev_key: u64 = 0;
1151    for parameter in parameters {
1152        encode_kvp_delta_pair(&mut prev_key, parameter, buf)?;
1153    }
1154    Ok(())
1155}
1156
1157/// Encode the Message Parameters of a control message.
1158fn encode_parameters(parameters: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
1159    encode_parameters_in(parameters, buf, true)
1160}
1161
1162/// Encode the Setup Parameters of a CLIENT_SETUP or SERVER_SETUP.
1163fn encode_setup_parameters(
1164    parameters: &[KeyValuePair],
1165    buf: &mut impl BufMut,
1166) -> Result<(), CodecError> {
1167    encode_parameters_in(parameters, buf, false)
1168}
1169
1170impl ControlMessage {
1171    pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
1172        check_ranges(self)?;
1173        check_discriminators(self)?;
1174        let mut payload = Vec::with_capacity(256);
1175        self.encode_payload(&mut payload)?;
1176
1177        if payload.len() > MAX_MESSAGE_LENGTH {
1178            return Err(CodecError::MessageTooLong(payload.len()));
1179        }
1180
1181        let msg_type = self.message_type();
1182        VarInt::from_usize(msg_type.id() as usize).encode(buf);
1183        // Draft-16: 16-bit length (big-endian)
1184        buf.put_u16(payload.len() as u16);
1185        buf.put_slice(&payload);
1186        Ok(())
1187    }
1188
1189    pub fn decode(buf: &mut impl Buf) -> Result<Self, CodecError> {
1190        let type_id = VarInt::decode(buf)?.into_inner();
1191        let msg_type =
1192            MessageType::from_id(type_id).ok_or(CodecError::UnknownMessageType(type_id))?;
1193        // Draft-16: 16-bit length (big-endian)
1194        if buf.remaining() < 2 {
1195            return Err(CodecError::UnexpectedEnd);
1196        }
1197        let payload_len = buf.get_u16() as usize;
1198        if buf.remaining() < payload_len {
1199            return Err(CodecError::UnexpectedEnd);
1200        }
1201        let payload_bytes = buf.copy_to_bytes(payload_len);
1202        let mut payload = &payload_bytes[..];
1203        let msg = match Self::decode_payload(msg_type, &mut payload) {
1204            Ok(msg) => msg,
1205            // The fields wanted more bytes than the Length allowed. This buffer
1206            // is already bounded by that Length, so running out inside it cannot
1207            // mean the message is still arriving - which is what the same error
1208            // means everywhere else, and why a reader loops on it rather than
1209            // closing. Here there is nothing left to arrive.
1210            Err(
1211                CodecError::UnexpectedEnd
1212                | CodecError::Kvp(crate::kvp::KvpError::UnexpectedEnd)
1213                | CodecError::Kvp(crate::kvp::KvpError::VarInt(
1214                    crate::varint::VarIntError::UnexpectedEnd,
1215                ))
1216                | CodecError::VarInt(crate::varint::VarIntError::UnexpectedEnd),
1217            ) => {
1218                return Err(CodecError::ControlMessageLengthMismatch {
1219                    declared: payload_len,
1220                    detail: "its fields ran past the end",
1221                });
1222            }
1223            Err(e) => return Err(e),
1224        };
1225        check_ranges(&msg)?;
1226        // The declared length is part of the message, not a hint. Bytes left over
1227        // after the fields have been read mean the sender and this reader disagree
1228        // about the shape of the message, and guessing which of the two is right
1229        // is how a trailing field gets silently dropped.
1230        if payload.has_remaining() {
1231            return Err(CodecError::ControlMessageLengthMismatch {
1232                declared: payload_len,
1233                detail: "its fields left bytes unread",
1234            });
1235        }
1236        Ok(msg)
1237    }
1238
1239    fn encode_payload(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
1240        match self {
1241            ControlMessage::ClientSetup(m) => {
1242                encode_setup_parameters(&m.parameters, buf)?;
1243            }
1244            ControlMessage::ServerSetup(m) => {
1245                encode_setup_parameters(&m.parameters, buf)?;
1246            }
1247            ControlMessage::GoAway(m) => {
1248                if m.new_session_uri.len() > MAX_GOAWAY_URI_LENGTH {
1249                    return Err(CodecError::GoAwayUriTooLong);
1250                }
1251                VarInt::from_usize(m.new_session_uri.len()).encode(buf);
1252                buf.put_slice(&m.new_session_uri);
1253            }
1254            ControlMessage::MaxRequestId(m) => {
1255                m.request_id.encode(buf);
1256            }
1257            ControlMessage::RequestsBlocked(m) => {
1258                m.maximum_request_id.encode(buf);
1259            }
1260            ControlMessage::RequestOk(m) => {
1261                m.request_id.encode(buf);
1262                encode_parameters(&m.parameters, buf)?;
1263            }
1264            ControlMessage::RequestError(m) => {
1265                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1266                    return Err(CodecError::ReasonPhraseTooLong);
1267                }
1268                m.request_id.encode(buf);
1269                m.error_code.encode(buf);
1270                m.retry_interval.encode(buf);
1271                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1272                buf.put_slice(&m.reason_phrase);
1273            }
1274            ControlMessage::Subscribe(m) => {
1275                m.request_id.encode(buf);
1276                m.track_namespace.validate(TrackNamespaceRules::for_draft(16))?;
1277                m.track_namespace.encode(buf);
1278                check_full_track_name(&m.track_namespace, &m.track_name)?;
1279                VarInt::from_usize(m.track_name.len()).encode(buf);
1280                buf.put_slice(&m.track_name);
1281                encode_parameters(&m.parameters, buf)?;
1282            }
1283            ControlMessage::SubscribeOk(m) => {
1284                m.request_id.encode(buf);
1285                m.track_alias.encode(buf);
1286                encode_parameters(&m.parameters, buf)?;
1287                encode_track_extensions(&m.track_extensions, buf)?;
1288            }
1289            ControlMessage::RequestUpdate(m) => {
1290                m.request_id.encode(buf);
1291                m.existing_request_id.encode(buf);
1292                encode_parameters(&m.parameters, buf)?;
1293            }
1294            ControlMessage::Unsubscribe(m) => {
1295                m.request_id.encode(buf);
1296            }
1297            ControlMessage::Publish(m) => {
1298                m.request_id.encode(buf);
1299                m.track_namespace.validate(TrackNamespaceRules::for_draft(16))?;
1300                m.track_namespace.encode(buf);
1301                check_full_track_name(&m.track_namespace, &m.track_name)?;
1302                VarInt::from_usize(m.track_name.len()).encode(buf);
1303                buf.put_slice(&m.track_name);
1304                m.track_alias.encode(buf);
1305                encode_parameters(&m.parameters, buf)?;
1306                encode_track_extensions(&m.track_extensions, buf)?;
1307            }
1308            ControlMessage::PublishOk(m) => {
1309                m.request_id.encode(buf);
1310                encode_parameters(&m.parameters, buf)?;
1311            }
1312            ControlMessage::PublishDone(m) => {
1313                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1314                    return Err(CodecError::ReasonPhraseTooLong);
1315                }
1316                m.request_id.encode(buf);
1317                m.status_code.encode(buf);
1318                m.stream_count.encode(buf);
1319                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1320                buf.put_slice(&m.reason_phrase);
1321            }
1322            ControlMessage::PublishNamespace(m) => {
1323                m.request_id.encode(buf);
1324                m.track_namespace.validate(TrackNamespaceRules::for_draft(16))?;
1325                m.track_namespace.encode(buf);
1326                encode_parameters(&m.parameters, buf)?;
1327            }
1328            ControlMessage::PublishNamespaceDone(m) => {
1329                m.request_id.encode(buf);
1330            }
1331            ControlMessage::PublishNamespaceCancel(m) => {
1332                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
1333                    return Err(CodecError::ReasonPhraseTooLong);
1334                }
1335                m.request_id.encode(buf);
1336                m.error_code.encode(buf);
1337                VarInt::from_usize(m.reason_phrase.len()).encode(buf);
1338                buf.put_slice(&m.reason_phrase);
1339            }
1340            ControlMessage::Namespace(m) => {
1341                m.namespace_suffix.validate(TrackNamespaceRules {
1342                    min_fields: 0,
1343                    ..TrackNamespaceRules::for_draft(16)
1344                })?;
1345                m.namespace_suffix.encode(buf);
1346            }
1347            ControlMessage::NamespaceDone(m) => {
1348                m.namespace_suffix.validate(TrackNamespaceRules {
1349                    min_fields: 0,
1350                    ..TrackNamespaceRules::for_draft(16)
1351                })?;
1352                m.namespace_suffix.encode(buf);
1353            }
1354            ControlMessage::SubscribeNamespace(m) => {
1355                m.request_id.encode(buf);
1356                // Section 9.25 gives the prefix its own field-count range:
1357                // "A Track Namespace structure as described in Section 2.4.1
1358                // with between 0 and 32 Track Namespace Fields", and its
1359                // session-closing clause names only "greater than than 32
1360                // Track Namespace Fields". The general rule in Section 2.4.1
1361                // closes the session on "0 or greater than 32", so a prefix is
1362                // the one position where an empty namespace is legal — it is
1363                // the prefix that matches every namespace.
1364                //
1365                // Only the field count is relaxed. The other Section 2.4.1
1366                // rules still apply, and one of them is easy to conflate with
1367                // this: "Each Track Namespace Field Value MUST contain at least
1368                // one byte." A prefix of zero fields is permitted; a prefix
1369                // holding a field of length zero is not, and inheriting the
1370                // rest of the draft-16 rules is what keeps that refusal.
1371                m.namespace_prefix.validate(TrackNamespaceRules {
1372                    min_fields: 0,
1373                    ..TrackNamespaceRules::for_draft(16)
1374                })?;
1375                m.namespace_prefix.encode(buf);
1376                m.subscribe_options.encode(buf);
1377                encode_parameters(&m.parameters, buf)?;
1378            }
1379            ControlMessage::TrackStatus(m) => {
1380                m.request_id.encode(buf);
1381                m.track_namespace.validate(TrackNamespaceRules::for_draft(16))?;
1382                m.track_namespace.encode(buf);
1383                check_full_track_name(&m.track_namespace, &m.track_name)?;
1384                VarInt::from_usize(m.track_name.len()).encode(buf);
1385                buf.put_slice(&m.track_name);
1386                encode_parameters(&m.parameters, buf)?;
1387            }
1388            ControlMessage::Fetch(m) => {
1389                m.request_id.encode(buf);
1390                VarInt::from_usize(m.fetch_type as usize).encode(buf);
1391                match &m.fetch_payload {
1392                    FetchPayload::Standalone {
1393                        track_namespace,
1394                        track_name,
1395                        start_group,
1396                        start_object,
1397                        end_group,
1398                        end_object,
1399                    } => {
1400                        track_namespace.validate(TrackNamespaceRules::for_draft(16))?;
1401                        track_namespace.encode(buf);
1402                        check_full_track_name(track_namespace, track_name)?;
1403                        VarInt::from_usize(track_name.len()).encode(buf);
1404                        buf.put_slice(track_name);
1405                        start_group.encode(buf);
1406                        start_object.encode(buf);
1407                        end_group.encode(buf);
1408                        end_object.encode(buf);
1409                    }
1410                    FetchPayload::Joining { joining_request_id, joining_start } => {
1411                        joining_request_id.encode(buf);
1412                        joining_start.encode(buf);
1413                    }
1414                }
1415                encode_parameters(&m.parameters, buf)?;
1416            }
1417            ControlMessage::FetchOk(m) => {
1418                m.request_id.encode(buf);
1419                buf.put_u8(m.end_of_track);
1420                m.end_group.encode(buf);
1421                m.end_object.encode(buf);
1422                encode_parameters(&m.parameters, buf)?;
1423                encode_track_extensions(&m.track_extensions, buf)?;
1424            }
1425            ControlMessage::FetchCancel(m) => {
1426                m.request_id.encode(buf);
1427            }
1428        }
1429        Ok(())
1430    }
1431
1432    fn decode_payload(msg_type: MessageType, buf: &mut impl Buf) -> Result<Self, CodecError> {
1433        match msg_type {
1434            MessageType::ClientSetup => {
1435                let parameters = decode_setup_parameters(buf)?;
1436                Ok(ControlMessage::ClientSetup(ClientSetup { parameters }))
1437            }
1438            MessageType::ServerSetup => {
1439                let parameters = decode_setup_parameters(buf)?;
1440                Ok(ControlMessage::ServerSetup(ServerSetup { parameters }))
1441            }
1442            MessageType::GoAway => {
1443                let uri_len = VarInt::decode(buf)?.into_inner() as usize;
1444                if uri_len > MAX_GOAWAY_URI_LENGTH {
1445                    return Err(CodecError::GoAwayUriTooLong);
1446                }
1447                let uri = read_bytes(buf, uri_len)?;
1448                Ok(ControlMessage::GoAway(GoAway { new_session_uri: uri }))
1449            }
1450            MessageType::MaxRequestId => {
1451                let request_id = VarInt::decode(buf)?;
1452                Ok(ControlMessage::MaxRequestId(MaxRequestId { request_id }))
1453            }
1454            MessageType::RequestsBlocked => {
1455                let maximum_request_id = VarInt::decode(buf)?;
1456                Ok(ControlMessage::RequestsBlocked(RequestsBlocked { maximum_request_id }))
1457            }
1458            MessageType::RequestOk => {
1459                let request_id = VarInt::decode(buf)?;
1460                let parameters = decode_parameters(buf)?;
1461                Ok(ControlMessage::RequestOk(RequestOk { request_id, parameters }))
1462            }
1463            MessageType::RequestError => {
1464                let request_id = VarInt::decode(buf)?;
1465                let error_code = VarInt::decode(buf)?;
1466                let retry_interval = VarInt::decode(buf)?;
1467                let reason_phrase = read_reason_phrase(buf)?;
1468                Ok(ControlMessage::RequestError(RequestError {
1469                    request_id,
1470                    error_code,
1471                    retry_interval,
1472                    reason_phrase,
1473                }))
1474            }
1475            MessageType::Subscribe => {
1476                let request_id = VarInt::decode(buf)?;
1477                let track_namespace =
1478                    TrackNamespace::decode_rules(buf, TrackNamespaceRules::for_draft(16))?;
1479                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1480                let track_name = read_bytes(buf, track_name_len)?;
1481                check_full_track_name(&track_namespace, &track_name)?;
1482                let parameters = decode_parameters(buf)?;
1483                Ok(ControlMessage::Subscribe(Subscribe {
1484                    request_id,
1485                    track_namespace,
1486                    track_name,
1487                    parameters,
1488                }))
1489            }
1490            MessageType::SubscribeOk => {
1491                let request_id = VarInt::decode(buf)?;
1492                let track_alias = VarInt::decode(buf)?;
1493                let parameters = decode_parameters(buf)?;
1494                let track_extensions = decode_track_extensions(buf)?;
1495                Ok(ControlMessage::SubscribeOk(SubscribeOk {
1496                    request_id,
1497                    track_alias,
1498                    parameters,
1499                    track_extensions,
1500                }))
1501            }
1502            MessageType::RequestUpdate => {
1503                let request_id = VarInt::decode(buf)?;
1504                let existing_request_id = VarInt::decode(buf)?;
1505                let parameters = decode_parameters(buf)?;
1506                Ok(ControlMessage::RequestUpdate(RequestUpdate {
1507                    request_id,
1508                    existing_request_id,
1509                    parameters,
1510                }))
1511            }
1512            MessageType::Unsubscribe => {
1513                let request_id = VarInt::decode(buf)?;
1514                Ok(ControlMessage::Unsubscribe(Unsubscribe { request_id }))
1515            }
1516            MessageType::Publish => {
1517                let request_id = VarInt::decode(buf)?;
1518                let track_namespace =
1519                    TrackNamespace::decode_rules(buf, TrackNamespaceRules::for_draft(16))?;
1520                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1521                let track_name = read_bytes(buf, track_name_len)?;
1522                check_full_track_name(&track_namespace, &track_name)?;
1523                let track_alias = VarInt::decode(buf)?;
1524                let parameters = decode_parameters(buf)?;
1525                let track_extensions = decode_track_extensions(buf)?;
1526                Ok(ControlMessage::Publish(Publish {
1527                    request_id,
1528                    track_namespace,
1529                    track_name,
1530                    track_alias,
1531                    parameters,
1532                    track_extensions,
1533                }))
1534            }
1535            MessageType::PublishOk => {
1536                let request_id = VarInt::decode(buf)?;
1537                let parameters = decode_parameters(buf)?;
1538                Ok(ControlMessage::PublishOk(PublishOk { request_id, parameters }))
1539            }
1540            MessageType::PublishDone => {
1541                let request_id = VarInt::decode(buf)?;
1542                let status_code = VarInt::decode(buf)?;
1543                let stream_count = VarInt::decode(buf)?;
1544                let reason_phrase = read_reason_phrase(buf)?;
1545                Ok(ControlMessage::PublishDone(PublishDone {
1546                    request_id,
1547                    status_code,
1548                    stream_count,
1549                    reason_phrase,
1550                }))
1551            }
1552            MessageType::PublishNamespace => {
1553                let request_id = VarInt::decode(buf)?;
1554                let track_namespace =
1555                    TrackNamespace::decode_rules(buf, TrackNamespaceRules::for_draft(16))?;
1556                let parameters = decode_parameters(buf)?;
1557                Ok(ControlMessage::PublishNamespace(PublishNamespace {
1558                    request_id,
1559                    track_namespace,
1560                    parameters,
1561                }))
1562            }
1563            MessageType::PublishNamespaceDone => {
1564                let request_id = VarInt::decode(buf)?;
1565                Ok(ControlMessage::PublishNamespaceDone(PublishNamespaceDone { request_id }))
1566            }
1567            MessageType::PublishNamespaceCancel => {
1568                let request_id = VarInt::decode(buf)?;
1569                let error_code = VarInt::decode(buf)?;
1570                let reason_phrase = read_reason_phrase(buf)?;
1571                Ok(ControlMessage::PublishNamespaceCancel(PublishNamespaceCancel {
1572                    request_id,
1573                    error_code,
1574                    reason_phrase,
1575                }))
1576            }
1577            MessageType::Namespace => {
1578                let namespace_suffix = TrackNamespace::decode_allow_empty(buf)?;
1579                Ok(ControlMessage::Namespace(Namespace { namespace_suffix }))
1580            }
1581            MessageType::NamespaceDone => {
1582                let namespace_suffix = TrackNamespace::decode_allow_empty(buf)?;
1583                Ok(ControlMessage::NamespaceDone(NamespaceDone { namespace_suffix }))
1584            }
1585            MessageType::SubscribeNamespace => {
1586                let request_id = VarInt::decode(buf)?;
1587                // Section 9.25 permits a prefix of zero fields; see the encode
1588                // arm. The reader that allows it still holds the fields to
1589                // draft-16's content rules, so a zero-length field stays
1590                // refused.
1591                let namespace_prefix = TrackNamespace::decode_allow_empty(buf)?;
1592                let subscribe_options = VarInt::decode(buf)?;
1593                let parameters = decode_parameters(buf)?;
1594                Ok(ControlMessage::SubscribeNamespace(SubscribeNamespace {
1595                    request_id,
1596                    namespace_prefix,
1597                    subscribe_options,
1598                    parameters,
1599                }))
1600            }
1601            MessageType::TrackStatus => {
1602                let request_id = VarInt::decode(buf)?;
1603                let track_namespace =
1604                    TrackNamespace::decode_rules(buf, TrackNamespaceRules::for_draft(16))?;
1605                let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1606                let track_name = read_bytes(buf, track_name_len)?;
1607                check_full_track_name(&track_namespace, &track_name)?;
1608                let parameters = decode_parameters(buf)?;
1609                Ok(ControlMessage::TrackStatus(TrackStatus {
1610                    request_id,
1611                    track_namespace,
1612                    track_name,
1613                    parameters,
1614                }))
1615            }
1616            MessageType::Fetch => {
1617                let request_id = VarInt::decode(buf)?;
1618                let fetch_type_val = VarInt::decode(buf)?.into_inner();
1619                let fetch_type = FetchType::from_u64(fetch_type_val)
1620                    .ok_or(CodecError::InvalidFetchType(fetch_type_val))?;
1621                let fetch_payload = match fetch_type {
1622                    FetchType::Standalone => {
1623                        let track_namespace =
1624                            TrackNamespace::decode_rules(buf, TrackNamespaceRules::for_draft(16))?;
1625                        let track_name_len = VarInt::decode(buf)?.into_inner() as usize;
1626                        let track_name = read_bytes(buf, track_name_len)?;
1627                        check_full_track_name(&track_namespace, &track_name)?;
1628                        let start_group = VarInt::decode(buf)?;
1629                        let start_object = VarInt::decode(buf)?;
1630                        let end_group = VarInt::decode(buf)?;
1631                        let end_object = VarInt::decode(buf)?;
1632                        FetchPayload::Standalone {
1633                            track_namespace,
1634                            track_name,
1635                            start_group,
1636                            start_object,
1637                            end_group,
1638                            end_object,
1639                        }
1640                    }
1641                    FetchType::RelativeJoining | FetchType::AbsoluteJoining => {
1642                        let joining_request_id = VarInt::decode(buf)?;
1643                        let joining_start = VarInt::decode(buf)?;
1644                        FetchPayload::Joining { joining_request_id, joining_start }
1645                    }
1646                };
1647                let parameters = decode_parameters(buf)?;
1648                Ok(ControlMessage::Fetch(Fetch {
1649                    request_id,
1650                    fetch_type,
1651                    fetch_payload,
1652                    parameters,
1653                }))
1654            }
1655            MessageType::FetchOk => {
1656                let request_id = VarInt::decode(buf)?;
1657                let end_of_track = read_u8(buf)?;
1658                let end_group = VarInt::decode(buf)?;
1659                let end_object = VarInt::decode(buf)?;
1660                let parameters = decode_parameters(buf)?;
1661                let track_extensions = decode_track_extensions(buf)?;
1662                Ok(ControlMessage::FetchOk(FetchOk {
1663                    request_id,
1664                    end_of_track,
1665                    end_group,
1666                    end_object,
1667                    parameters,
1668                    track_extensions,
1669                }))
1670            }
1671            MessageType::FetchCancel => {
1672                let request_id = VarInt::decode(buf)?;
1673                Ok(ControlMessage::FetchCancel(FetchCancel { request_id }))
1674            }
1675        }
1676    }
1677
1678    pub fn message_type(&self) -> MessageType {
1679        match self {
1680            ControlMessage::ClientSetup(_) => MessageType::ClientSetup,
1681            ControlMessage::ServerSetup(_) => MessageType::ServerSetup,
1682            ControlMessage::GoAway(_) => MessageType::GoAway,
1683            ControlMessage::MaxRequestId(_) => MessageType::MaxRequestId,
1684            ControlMessage::RequestsBlocked(_) => MessageType::RequestsBlocked,
1685            ControlMessage::RequestOk(_) => MessageType::RequestOk,
1686            ControlMessage::RequestError(_) => MessageType::RequestError,
1687            ControlMessage::Subscribe(_) => MessageType::Subscribe,
1688            ControlMessage::SubscribeOk(_) => MessageType::SubscribeOk,
1689            ControlMessage::RequestUpdate(_) => MessageType::RequestUpdate,
1690            ControlMessage::Unsubscribe(_) => MessageType::Unsubscribe,
1691            ControlMessage::Publish(_) => MessageType::Publish,
1692            ControlMessage::PublishOk(_) => MessageType::PublishOk,
1693            ControlMessage::PublishDone(_) => MessageType::PublishDone,
1694            ControlMessage::PublishNamespace(_) => MessageType::PublishNamespace,
1695            ControlMessage::PublishNamespaceDone(_) => MessageType::PublishNamespaceDone,
1696            ControlMessage::PublishNamespaceCancel(_) => MessageType::PublishNamespaceCancel,
1697            ControlMessage::Namespace(_) => MessageType::Namespace,
1698            ControlMessage::NamespaceDone(_) => MessageType::NamespaceDone,
1699            ControlMessage::SubscribeNamespace(_) => MessageType::SubscribeNamespace,
1700            ControlMessage::TrackStatus(_) => MessageType::TrackStatus,
1701            ControlMessage::Fetch(_) => MessageType::Fetch,
1702            ControlMessage::FetchOk(_) => MessageType::FetchOk,
1703            ControlMessage::FetchCancel(_) => MessageType::FetchCancel,
1704        }
1705    }
1706}