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