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