Skip to main content

moqtap_codec/draft23/
message.rs

1//! Draft-23 control message encoding and decoding.
2//!
3//! - The Message Length is a `vi64` (Section 9, Figure 6), bounded by the
4//!   receiver's MAX_CONTROL_MESSAGE_SIZE (Section 9.1.8), 65535 unless the
5//!   receiver advertised more. [`ControlMessage::decode`] and
6//!   [`ControlMessage::encode`] use that default;
7//!   [`ControlMessage::decode_with_limit`] and
8//!   [`ControlMessage::encode_with_limit`] take the limit.
9//! - FETCH is answered by REQUEST_OK; type 0x18 is reserved (Section 9,
10//!   Table 5).
11//! - REQUEST_ERROR ends in Error Details, Key-Value-Pairs (Section 9.4.1).
12//! - NAMESPACE carries a parameter block (Section 9.15, Figure 20).
13//! - `FILL_PARAMETERS` (0x23) is a parameter count followed by that many
14//!   parameters, with no length (Section 9.19.15).
15//! - `PAUSED` (0x11, Section 9.19.18) and `SUBSCRIBE_TRACKS_ID` (0x36,
16//!   Section 9.19.21).
17//!
18//! Every section, table and figure reference in this module is draft-23's own.
19
20use crate::auth_token::{AuthorizationToken, AUTH_TOKEN_PARAMETER};
21use crate::error::MAX_FULL_TRACK_NAME_LENGTH;
22pub use crate::error::{
23    CodecError, MAX_GOAWAY_URI_LENGTH, MAX_MESSAGE_LENGTH, MAX_NAMESPACE_TUPLE_SIZE,
24    MAX_REASON_PHRASE_LENGTH,
25};
26use crate::kvp::{KeyValuePair, KvpError, KvpValue, MAX_KVP_VALUE_LEN};
27use crate::types::*;
28use crate::varint::{Moqt18 as Wire, VarInt};
29use bytes::{Buf, BufMut};
30
31// ============================================================
32// Parameter encoding helpers for draft-23
33// ============================================================
34
35/// How a parameter value is encoded on the wire.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37enum ParamEncoding {
38    /// Bare varint.
39    Varint,
40    /// Single byte (uint8).
41    Uint8,
42    /// Two consecutive varints (group, object).
43    Location,
44    /// Length-prefixed bytes.
45    LengthPrefixed,
46    /// A Track Namespace as defined in draft-23 Section 8.7: a varint field
47    /// count followed by that many length-prefixed fields.
48    ///
49    /// The fifth value encoding draft-23 Section 9.19 lists: "Track Namespace:
50    /// A sequence of length-prefixed fields (Section 8.7)". TRACK_NAMESPACE_PREFIX
51    /// is the parameter that uses it; the field count is the only length the
52    /// wire carries.
53    TrackNamespaceValue,
54    /// A `Location Filter Type` followed by the zero to four `vi64` fields that
55    /// type names (draft-23 Section 9.19.9).
56    ///
57    /// None of the five encodings Section 9.19 lists fits it. The parameter
58    /// definition states its own structure, and that structure has no length:
59    /// the type is the only thing that says where the value ends.
60    LocationFilter,
61    /// A `Number of Parameters` count and that many parameters (Section
62    /// 9.19.15). Like a LOCATION_FILTER it has no length, so the inner
63    /// parameters are read one by one to find where it ends.
64    FillParameters,
65}
66
67fn param_encoding(key: u64) -> Option<ParamEncoding> {
68    match key {
69        // 0x02 = OBJECT_DELIVERY_TIMEOUT (Section 9.19.4)
70        // 0x04 = RENDEZVOUS_TIMEOUT (Section 9.19.6). Not MAX_CACHE_DURATION:
71        //        that is Property Type 0x04 in the separate Properties
72        //        registry (Section 16.8), a different namespace that happens
73        //        to reuse the number.
74        // 0x06 = SUBGROUP_DELIVERY_TIMEOUT (Section 9.19.3)
75        // 0x08 = EXPIRES (Section 9.19.16)
76        // 0x0A = FILL_TIMEOUT (Section 9.19.5)
77        // 0x32 = NEW_GROUP_REQUEST (Section 9.19.19)
78        // 0x36 = SUBSCRIBE_TRACKS_ID. Section 9.19.21: "The
79        //        SUBSCRIBE_TRACKS_ID parameter (Parameter Type 0x36) is a
80        //        varint."
81        0x02 | 0x04 | 0x06 | 0x08 | 0x0A | 0x32 | 0x36 => Some(ParamEncoding::Varint),
82        // 0x11 = PAUSED. Section 9.19.18: "The PAUSED parameter (Parameter
83        //        Type 0x11) is a uint8."
84        // 0x20 = SUBSCRIBER_PRIORITY, 0x22 = GROUP_ORDER, and
85        // 0x35 = INCLUDE_PROPERTIES. Section 9.19.22: "The
86        //        INCLUDE_PROPERTIES parameter (Parameter Type 0x35) is a
87        //        uint8."
88        0x11 | 0x20 | 0x22 | 0x35 => Some(ParamEncoding::Uint8),
89        // 0x09 = LARGEST_OBJECT. Draft-23 Section 9.19.17: "The LARGEST_OBJECT
90        //        parameter (Parameter Type 0x9) is a Location." A Location is
91        //        two consecutive varints (Section 9.19), with no length ahead
92        //        of them. The type is odd, which on a Key-Value-Pair would mean
93        //        length-prefixed; Message Parameters are not Key-Value-Pairs
94        //        and the odd/even rule does not reach them.
95        0x09 => Some(ParamEncoding::Location),
96        // 0x34 = TRACK_NAMESPACE_PREFIX. Section 9.19.20: it "uses the Track
97        //        Namespace encoding described in Section 8.7".
98        0x34 => Some(ParamEncoding::TrackNamespaceValue),
99        // 0x21 = LOCATION_FILTER. Section 9.19.9: "The Location Filter Type
100        //        dictates which optional variable-length integer fields follow,
101        //        and how they are interpreted." No length precedes the type,
102        //        and the type is odd for the same reason 0x09's is: the
103        //        odd/even rule is a Key-Value-Pair rule and does not reach
104        //        Message Parameters.
105        0x21 => Some(ParamEncoding::LocationFilter),
106        // 0x23 = FILL_PARAMETERS. Section 9.19.15: "Its value is a Number of
107        //        Parameters (vi64) followed by that many Parameters that apply
108        //        to the fill fetch stream". No length precedes the count.
109        0x23 => Some(ParamEncoding::FillParameters),
110        // 0x03 = AUTHORIZATION_TOKEN
111        // 0x25 = SUBGROUP_FILTER, 0x26 = OBJECTID_FILTER, 0x27 = PRIORITY_FILTER,
112        // 0x28 = OBJECT_PROPERTY_FILTER, 0x29 = TRACK_PROPERTY_FILTER
113        //        (Range Filters, Section 8.6)
114        0x03 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 => Some(ParamEncoding::LengthPrefixed),
115        _ => None,
116    }
117}
118
119/// Whether `value` is inside the range draft-23 allows for a uint8-valued
120/// parameter.
121///
122/// Three of the four uint8 parameters restrict their range and say the receiver
123/// MUST close the session with INVALID_PARAMETER on anything outside it:
124/// GROUP_ORDER allows only Ascending (0x1) and Descending (0x2) (Section
125/// 9.19.8), PAUSED allows only 0 and 1 (Section 9.19.18), and
126/// INCLUDE_PROPERTIES allows only 0 and 1 (Section 9.19.22).
127/// SUBSCRIBER_PRIORITY (Section 9.19.7) uses the whole 0-255 range,
128/// so it has no entry here.
129fn uint8_value_in_range(key: u64, value: u8) -> bool {
130    match key {
131        // PAUSED (0x11), Section 9.19.18: "The allowed values are 0
132        // (unpaused) or 1 (paused). If an endpoint receives a value outside
133        // this range, it MUST close the session with INVALID_PARAMETER."
134        0x11 => value <= 1,
135        // GROUP_ORDER (0x22)
136        0x22 => value == 1 || value == 2,
137        // INCLUDE_PROPERTIES (0x35), Section 9.19.22: "The allowed values are
138        // 0 (do not send Properties) or 1 (send Properties), and the default
139        // is 1. If an endpoint receives a value outside this range, it MUST
140        // close the session with INVALID_PARAMETER."
141        0x35 => value <= 1,
142        _ => true,
143    }
144}
145
146/// AUTHORIZATION TOKEN, Parameter Type 0x03.
147const AUTHORIZATION_TOKEN: u64 = 0x03;
148
149/// Whether draft-23 lets a message carry parameter type `key` more than once.
150///
151/// Section 9.19 states the default: "Senders MUST NOT repeat the same Parameter
152/// Type in a message unless the parameter definition explicitly allows multiple
153/// instances of that type to be sent in a single message." Two definitions do.
154///
155/// * `AUTHORIZATION_TOKEN` (0x03), Section 8.9: "An Authorization Token MAY
156///   be repeated within a message as long as the combination of Token Type and
157///   Token Value are unique after resolving any aliases."
158/// * The five Range Filters (0x25 through 0x29), Section 3.3.2: "The Track Property filter parameter MAY appear multiple times in a
159///   SUBSCRIBE_TRACKS message or REQUEST_UPDATE for it. All other filter
160///   parameters MAY appear multiple times in a FETCH, SUBSCRIBE,
161///   SUBSCRIBE_TRACKS, or REQUEST_UPDATE (on a subscription, from the subscriber
162///   only) message."
163///
164/// # A zero `Type Delta` is "the same type again", not an error
165///
166/// The two rules interact, and **the draft does not say how**. Section 9.19 also
167/// requires that "Parameters MUST be serialized in ascending order by Type", so
168/// a second instance of a repeatable type produces a `Type Delta` of 0 — well
169/// formed only if the decoder reads a zero delta as a repeat rather than as a
170/// malformation. That reading is the one taken here; the alternative makes
171/// Section 3.3.2's permission unusable, because there is no other encoding for
172/// a second filter of the same type.
173///
174/// What the filters may **not** do is repeat the same (Parameter Type, SetID,
175/// Property Type) triple, and Section 3.3.2 answers that with a REQUEST_ERROR
176/// carrying INVALID_FILTER rather than with a session close. A reply an endpoint
177/// sends is not a frame a decoder refuses, so nothing here enforces it — see
178/// [`crate::range_filter`] for the reader an endpoint uses to decide.
179fn parameter_may_repeat(key: u64) -> bool {
180    matches!(key, AUTHORIZATION_TOKEN | 0x25..=0x29)
181}
182
183/// Add a delta to the previous delta-encoded key.
184///
185/// Draft-23 Section 8.3: "The previous Type value plus the Delta Type MUST NOT
186/// be greater than 2^64 - 1. If a Delta Type is received that would be too
187/// large, the Session MUST be closed with DELTA_ENCODING_OVERFLOW." Section
188/// 9.19 says the same of a Message Parameter's Type Delta.
189fn add_delta(prev_key: u64, delta: u64) -> Result<u64, CodecError> {
190    prev_key.checked_add(delta).ok_or(CodecError::KeyDeltaOverflow(prev_key, delta))
191}
192
193/// Hold a namespace-plus-name pair to the Full Track Name cap.
194///
195/// Draft-23 Section 8.7: "The maximum total length of a Full Track Name is
196/// 4,096 bytes. The length of a Full Track Name is computed as the sum of the
197/// Track Namespace Field Length fields and the Track Name Length field... If an
198/// endpoint receives a Track Namespace or a Full Track Name exceeding 4,096
199/// bytes, it MUST close the session with FIELD_LENGTH_EXCEEDED."
200///
201/// The namespace half of that sentence is enforced inside the namespace decoder,
202/// which is the only place that sees a namespace with no name beside it. This is
203/// the other half, and it has to live where the two are decoded together: a
204/// namespace at 4,000 bytes and a name at 500 are each legal alone.
205fn check_full_track_name(namespace: &TrackNamespace, track_name: &[u8]) -> Result<(), CodecError> {
206    let total = namespace.field_bytes_len().saturating_add(track_name.len());
207    if total > MAX_FULL_TRACK_NAME_LENGTH {
208        return Err(CodecError::TrackNameTooLong);
209    }
210    Ok(())
211}
212
213/// Refuse an empty Track Name.
214///
215/// Draft-23 Section 2.4.1: "Each Track Name MUST contain at least one byte. If
216/// an endpoint receives a Track Name with a length of 0, it MUST close the
217/// session with a PROTOCOL_VIOLATION." The REDIRECT Error Detail is exempt:
218/// Section 9.4.2.1 requires its Track Name to be empty for namespace-scoped
219/// requests.
220///
221/// Decoders call it after the rest of the body, so a DELTA_ENCODING_OVERFLOW
222/// or FIELD_LENGTH_EXCEEDED later in the message is the one reported. Section
223/// 12.2: "When more than one code applies, an endpoint uses
224/// DELTA_ENCODING_OVERFLOW or FIELD_LENGTH_EXCEEDED in preference to the
225/// other codes."
226fn check_track_name(track_name: &[u8]) -> Result<(), CodecError> {
227    if track_name.is_empty() {
228        return Err(CodecError::EmptyTrackName);
229    }
230    Ok(())
231}
232
233/// Hold every AUTHORIZATION TOKEN parameter to the Token structure it names.
234///
235/// Section 8.9: "If the Token structure cannot be decoded, including an
236/// unknown Alias Type, the receiver MUST close the Session with
237/// MALFORMED_AUTH_TOKEN." Both namespaces carry the type on this draft, and
238/// both reach here.
239fn check_authorization_tokens(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
240    for parameter in parameters {
241        let key = parameter.key.into_inner();
242        if key != AUTH_TOKEN_PARAMETER {
243            continue;
244        }
245        match &parameter.value {
246            KvpValue::Bytes(value) => {
247                AuthorizationToken::decode_moqt::<Wire>(key, value).map_err(|e| match e {
248                    CodecError::KeyValueFormatting { key, detail } => {
249                        CodecError::MalformedAuthToken { key, detail }
250                    }
251                    other => other,
252                })?;
253            }
254            // Unreachable from the decoder, which picks the shape from the
255            // type and finds this one length-prefixed. A caller that built the
256            // pair in memory can still get here.
257            KvpValue::Varint(_) => {
258                return Err(CodecError::MalformedAuthToken {
259                    key,
260                    detail: "its value is a bare varint where the type defines a Token structure",
261                });
262            }
263        }
264    }
265    Ok(())
266}
267
268/// The parameter types draft-23 Section 9.19.15, Table 7 permits inside a
269/// `FILL_PARAMETERS` value, in ascending order. "An endpoint that receives a
270/// parameter inside FILL_PARAMETERS that is not listed above MUST close the
271/// session with INVALID_PARAMETER."
272const FILL_PARAMETERS_ALLOWED: &[u64] = &[0x0A, 0x20, 0x21, 0x22, 0x25, 0x26, 0x27, 0x28];
273
274/// The LOCATION_FILTER parameter type, draft-23 Section 9.19.9.
275pub const LOCATION_FILTER: u64 = 0x21;
276
277/// The FILL_PARAMETERS parameter type, draft-23 Section 9.19.15.
278pub const FILL_PARAMETERS: u64 = 0x23;
279
280/// The `Location Filter Type` values draft-23 Section 9.19.9 assigns, named as
281/// Table 6 names them.
282pub mod location_filter_types {
283    /// 0x00, None: "no fields follow and there is no Location Filter".
284    pub const NONE: u64 = 0x00;
285    /// 0x01, Relative Start: "a relative StartGroup follows".
286    pub const RELATIVE_START: u64 = 0x01;
287    /// 0x02, Absolute Start: "StartGroup and StartObject follow".
288    pub const ABSOLUTE_START: u64 = 0x02;
289    /// 0x03, Absolute Start, Group End: "StartGroup, StartObject, and
290    /// EndGroupDelta follow".
291    pub const ABSOLUTE_START_GROUP_END: u64 = 0x03;
292    /// 0x04, Absolute Range: "StartGroup, StartObject, EndGroupDelta, and
293    /// EndObject follow".
294    pub const ABSOLUTE_RANGE: u64 = 0x04;
295    /// 0x05, Next Object: "no fields follow and it specifies the Next Object".
296    pub const NEXT_OBJECT: u64 = 0x05;
297}
298
299/// How many `vi64` fields follow a `Location Filter Type`, or `None` for a type
300/// draft-23 does not assign.
301///
302/// Section 9.19.9 gives one sentence per type and closes the list: "If an
303/// endpoint receives any other Location Filter Type, it MUST close the session
304/// with INVALID_PARAMETER." The fields are always a
305/// prefix of `StartGroup`, `StartObject`, `EndGroupDelta`, `EndObject`, so the
306/// count is all a reader needs to know which ones arrived.
307///
308/// Types 0x00 and 0x05 both carry nothing and mean opposite things — no filter
309/// at all, and a filter that starts at the Next Object — so a caller that wants
310/// the meaning switches on the type, never on the count.
311pub fn location_filter_field_count(filter_type: u64) -> Option<usize> {
312    use location_filter_types as T;
313    match filter_type {
314        T::NONE | T::NEXT_OBJECT => Some(0),
315        T::RELATIVE_START => Some(1),
316        T::ABSOLUTE_START => Some(2),
317        T::ABSOLUTE_START_GROUP_END => Some(3),
318        T::ABSOLUTE_RANGE => Some(4),
319        _ => None,
320    }
321}
322
323/// Read one `LOCATION_FILTER` value off `buf`: the `Location Filter Type`, then
324/// exactly the fields that type names.
325///
326/// `buf` is bounded by the enclosing message body, or by the enclosing
327/// `FILL_PARAMETERS` value, and nothing narrower: the parameter carries no
328/// length of its own. A field that would run past that bound is a parameter
329/// that is not the structure its type defines, which is
330/// [`CodecError::SubscriptionFilterMalformed`] rather than a short read — the
331/// frame around it arrived whole.
332///
333/// A type outside Section 9.19.9's list is
334/// [`CodecError::ParameterValueOutOfRange`], the INVALID_PARAMETER of Section
335/// 12.2 ("has a value outside its allowed range"), and it is refused before any
336/// field is read: the type is the only thing that
337/// says where the value ends, so past an unknown one there is nothing a reader
338/// can do but stop.
339fn read_location_filter(buf: &mut impl Buf) -> Result<(u64, Vec<u64>), CodecError> {
340    let filter_type = VarInt::decode_moqt::<Wire>(buf)
341        .map_err(|_| CodecError::SubscriptionFilterMalformed {
342            detail: "its Location Filter Type runs past the end of the message",
343        })?
344        .into_inner();
345    let count = location_filter_field_count(filter_type)
346        .ok_or(CodecError::ParameterValueOutOfRange { key: LOCATION_FILTER, value: filter_type })?;
347    let mut fields = Vec::with_capacity(count);
348    for _ in 0..count {
349        let field = VarInt::decode_moqt::<Wire>(buf).map_err(|_| {
350            CodecError::SubscriptionFilterMalformed {
351                detail: "a field its Location Filter Type names runs past the end of the message",
352            }
353        })?;
354        fields.push(field.into_inner());
355    }
356    Ok((filter_type, fields))
357}
358
359/// Write a `LOCATION_FILTER` value in its minimal encoding: the type, then the
360/// fields, each the shortest `vi64` that holds it.
361///
362/// The decoder stores what it read through this, so a value that arrived with
363/// a non-minimal varint anywhere in it — the type included, which Section 8.1
364/// permits like any other — re-encodes to different bytes. That is the same
365/// treatment a Location (0x09) gets, and it is what makes such a frame a
366/// non-canonical one rather than one this codec silently rewrites on relay.
367fn write_location_filter(filter_type: u64, fields: &[u64]) -> Vec<u8> {
368    let mut encoded = Vec::new();
369    VarInt::from_u64_moqt(filter_type).encode_moqt::<Wire>(&mut encoded);
370    for field in fields {
371        VarInt::from_u64_moqt(*field).encode_moqt::<Wire>(&mut encoded);
372    }
373    encoded
374}
375
376/// Decode a draft-23 `LOCATION_FILTER` value into its `Location Filter Type`
377/// and the fields that type names.
378///
379/// The value is the bytes a decoded [`KeyValuePair`] holds under type 0x21: the
380/// type and its fields, with no length ahead of them. The fields come back in
381/// wire order, `StartGroup`, `StartObject`, `EndGroupDelta`, `EndObject`, as
382/// many as [`location_filter_field_count`] gives for the type; Section 9.19.9,
383/// Table 6 says what each type means.
384///
385/// Refuses a type draft-23 does not assign with
386/// [`CodecError::ParameterValueOutOfRange`], and a value that holds fewer or more
387/// bytes than its type's fields with [`CodecError::SubscriptionFilterMalformed`].
388/// Every value the decoder stores passes; the refusals are for a value built in
389/// memory, which the encoder holds to the same rule before writing it.
390pub fn decode_location_filter(value: &[u8]) -> Result<(u64, Vec<u64>), CodecError> {
391    let mut cursor = value;
392    let (filter_type, fields) = read_location_filter(&mut cursor)?;
393    if cursor.has_remaining() {
394        return Err(CodecError::SubscriptionFilterMalformed {
395            detail: "bytes follow the fields its Location Filter Type names",
396        });
397    }
398    Ok((filter_type, fields))
399}
400
401/// Hold a decoded `LOCATION_FILTER` to the one arithmetic rule draft-23 states
402/// about it.
403///
404/// Section 9.19.9: "EndGroupDelta is delta encoded from StartGroup, but both the
405/// start and end groups are absolute, not relative to Largest Object. If
406/// StartGroup + EndGroupDelta exceeds 2^64 - 1, the endpoint MUST close the
407/// session with DELTA_ENCODING_OVERFLOW." The sum only exists on types 0x03 and
408/// 0x04, the two that carry an `EndGroupDelta`, which are the two whose field
409/// count reaches three.
410///
411/// There is deliberately no check that the end is at or after the start.
412/// `EndGroupDelta` is unsigned and added to `StartGroup`, so the end group can
413/// never precede the start group; and within one group draft-23 states no rule
414/// about `EndObject` being below `StartObject`. Section 3.3.1 says the opposite
415/// for subscriptions — "A Location Filter on a subscription is always valid,
416/// even if it specifies a range entirely before Largest Object" — so refusing
417/// one would close sessions over a sentence that is not there.
418fn check_location_filter_fields(fields: &[u64]) -> Result<(), CodecError> {
419    if fields.len() < 3 {
420        return Ok(());
421    }
422    let start_group = fields[0];
423    let delta = fields[2];
424    if start_group.checked_add(delta).is_none() {
425        return Err(CodecError::FilterEndGroupOverflow { start_group, delta });
426    }
427    Ok(())
428}
429
430/// Read one `FILL_PARAMETERS` value off `buf`: its `Number of Parameters` and
431/// that many parameters.
432///
433/// Section 9.19.15: "Its value is a Number of Parameters (vi64) followed by
434/// that many Parameters that apply to the fill fetch stream (see Section 3.4),
435/// encoded as if they were Parameters for a separate message (see Section
436/// 9.19)." Nothing states the value's length, so each inner parameter is read
437/// in the shape its type names, as a message's own are.
438///
439/// "The value of FILL_PARAMETERS is a separate parameter scope. Parameters
440/// inside it are not considered to appear in the enclosing message for the
441/// purposes of Section 9.19". The inner `Type Delta` chain therefore starts
442/// from 0, and the outer parameter after `FILL_PARAMETERS` deltas from `0x23`.
443///
444/// A type outside Table 7 is [`CodecError::ParameterOutOfScope`], reported
445/// against `FILL_PARAMETERS` itself. A type draft-23 does not define at all is
446/// [`CodecError::UnknownMessageParameter`], checked first.
447fn read_fill_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
448    let count = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
449    let mut params = crate::types::reserve_bounded(count, buf);
450    let mut prev_key: u64 = 0;
451
452    for i in 0..count {
453        let delta = VarInt::decode_moqt::<Wire>(buf)?.into_inner();
454        let abs_key = add_delta(prev_key, delta)?;
455        if i > 0 && delta == 0 && !parameter_may_repeat(abs_key) {
456            return Err(CodecError::DuplicateParameter(abs_key));
457        }
458        prev_key = abs_key;
459
460        let encoding =
461            param_encoding(abs_key).ok_or(CodecError::UnknownMessageParameter(abs_key))?;
462        if !FILL_PARAMETERS_ALLOWED.contains(&abs_key) {
463            return Err(CodecError::ParameterOutOfScope {
464                key: abs_key,
465                message_type: FILL_PARAMETERS,
466            });
467        }
468
469        let value = decode_parameter_value(encoding, abs_key, buf)?;
470        params.push(KeyValuePair { key: VarInt::from_u64_moqt(abs_key), value });
471    }
472    check_location_filters(&params)?;
473    Ok(params)
474}
475
476/// Write a `FILL_PARAMETERS` value: the count and the inner parameters, with
477/// no length ahead of them.
478fn write_fill_parameters(params: &[KeyValuePair]) -> Result<Vec<u8>, CodecError> {
479    for p in params {
480        let key = p.key.into_inner();
481        if param_encoding(key).is_none() {
482            return Err(CodecError::UnknownMessageParameter(key));
483        }
484        if !FILL_PARAMETERS_ALLOWED.contains(&key) {
485            return Err(CodecError::ParameterOutOfScope { key, message_type: FILL_PARAMETERS });
486        }
487    }
488    let mut encoded = Vec::new();
489    encode_parameters(params, &mut encoded)?;
490    Ok(encoded)
491}
492
493/// Decode the parameters a `FILL_PARAMETERS` value carries.
494///
495/// The value is the bytes a decoded [`KeyValuePair`] holds under type 0x23:
496/// the `Number of Parameters` and the parameters, with no length ahead of
497/// them. Refuses a value with bytes after its last parameter with
498/// [`CodecError::SubscriptionFilterMalformed`]; the decoder never stores one.
499pub fn decode_fill_parameters(value: &[u8]) -> Result<Vec<KeyValuePair>, CodecError> {
500    let mut cursor = value;
501    let params = read_fill_parameters(&mut cursor)?;
502    if cursor.has_remaining() {
503        return Err(CodecError::SubscriptionFilterMalformed {
504            detail: "bytes follow the parameters FILL_PARAMETERS counts",
505        });
506    }
507    Ok(params)
508}
509
510/// Encode `params` as a `FILL_PARAMETERS` value, the inverse of
511/// [`decode_fill_parameters`].
512pub fn encode_fill_parameters(params: &[KeyValuePair]) -> Result<Vec<u8>, CodecError> {
513    write_fill_parameters(params)
514}
515
516/// Hold every LOCATION_FILTER and FILL_PARAMETERS parameter to the structure
517/// its own type names.
518///
519/// Applied on both sides. A value the decoder refuses is one the peer must
520/// close the session over, so writing it is a way to end a session rather than
521/// a way to ask for anything.
522///
523/// The two are checked together because `FILL_PARAMETERS` can carry a
524/// `LOCATION_FILTER` of its own, and a filter that is malformed one level down
525/// is exactly as malformed. [`decode_fill_parameters`] recurses back into this
526/// function for that reason; the nesting bottoms out because Table 7 does not
527/// list `FILL_PARAMETERS` inside itself.
528///
529/// The values are otherwise decoded and discarded. What is kept is the refusal
530/// — each stays on its parameter as bytes, so a caller reads one through
531/// [`decode_location_filter`] or [`decode_fill_parameters`] when it wants the
532/// structure rather than the frame.
533///
534/// On decode the `LOCATION_FILTER` half can only find the overflow: the
535/// decoder read the value by its type, so its shape is already right. On
536/// encode it finds everything, because a value built in memory can name one
537/// type and carry another type's fields, and the encoder writes the value with
538/// no length that would let a receiver notice.
539fn check_location_filters(parameters: &[KeyValuePair]) -> Result<(), CodecError> {
540    for parameter in parameters {
541        let key = parameter.key.into_inner();
542        if key != LOCATION_FILTER && key != FILL_PARAMETERS {
543            continue;
544        }
545        match &parameter.value {
546            KvpValue::Bytes(value) if key == LOCATION_FILTER => {
547                check_location_filter_fields(&decode_location_filter(value)?.1)?;
548            }
549            KvpValue::Bytes(value) => {
550                decode_fill_parameters(value)?;
551            }
552            // Unreachable from the decoder, which stores both of these as
553            // bytes. A caller that built the pair in memory can still get here,
554            // and it is the same rule.
555            KvpValue::Varint(_) => {
556                return Err(CodecError::SubscriptionFilterMalformed {
557                    detail: "its value is a bare varint where the type defines a structure",
558                });
559            }
560        }
561    }
562    Ok(())
563}
564
565/// Read one parameter's value in the shape its type names.
566///
567/// Shared by the message's own parameter block and by the nested block inside
568/// `FILL_PARAMETERS`, so a type cannot be read one way in a message and another
569/// way in a fill.
570fn decode_parameter_value(
571    encoding: ParamEncoding,
572    abs_key: u64,
573    buf: &mut impl Buf,
574) -> Result<KvpValue, CodecError> {
575    Ok(match encoding {
576        ParamEncoding::Varint => KvpValue::Varint(VarInt::decode_moqt::<Wire>(buf)?),
577        ParamEncoding::Uint8 => {
578            if buf.remaining() < 1 {
579                return Err(CodecError::UnexpectedEnd);
580            }
581            let byte = buf.get_u8();
582            if !uint8_value_in_range(abs_key, byte) {
583                return Err(CodecError::ParameterValueOutOfRange {
584                    key: abs_key,
585                    value: byte as u64,
586                });
587            }
588            KvpValue::Varint(VarInt::from_u64_moqt(byte as u64))
589        }
590        ParamEncoding::Location => {
591            let group = VarInt::decode_moqt::<Wire>(buf)?;
592            let object = VarInt::decode_moqt::<Wire>(buf)?;
593            let mut encoded = Vec::new();
594            group.encode_moqt::<Wire>(&mut encoded);
595            object.encode_moqt::<Wire>(&mut encoded);
596            KvpValue::Bytes(encoded)
597        }
598        ParamEncoding::LengthPrefixed => {
599            let len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
600            KvpValue::Bytes(read_bytes(buf, len)?)
601        }
602        ParamEncoding::LocationFilter => {
603            let (filter_type, fields) = read_location_filter(buf)?;
604            KvpValue::Bytes(write_location_filter(filter_type, &fields))
605        }
606        // Stored re-encoded, as a LOCATION_FILTER is, so a value that arrived
607        // with a non-minimal varint inside it is a non-canonical frame.
608        ParamEncoding::FillParameters => {
609            let inner = read_fill_parameters(buf)?;
610            KvpValue::Bytes(write_fill_parameters(&inner)?)
611        }
612        ParamEncoding::TrackNamespaceValue => {
613            // A prefix of zero fields is legal: Section 2.4.1 puts a Track
614            // Namespace at "between 0 and 32 Track Namespace Fields", and
615            // an empty prefix matches every namespace.
616            let ns = TrackNamespace::decode_allow_empty_moqt::<Wire>(buf)?;
617            let mut encoded = Vec::new();
618            ns.encode_moqt::<Wire>(&mut encoded);
619            KvpValue::Bytes(encoded)
620        }
621    })
622}
623
624/// Decode a count-prefixed list of parameters with delta-encoded types.
625fn decode_parameters(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
626    let count = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
627    let mut params = crate::types::reserve_bounded(count, buf);
628    let mut prev_key: u64 = 0;
629
630    for i in 0..count {
631        let delta = VarInt::decode_moqt::<Wire>(buf)?.into_inner();
632        let abs_key = add_delta(prev_key, delta)?;
633        // Types ascend, so a repeat is always a zero delta against the
634        // parameter before it. Draft-23 Section 9.19: "Receivers SHOULD check
635        // that there are no unexpected duplicate parameters and close the
636        // session with INVALID_PARAMETER if found."
637        //
638        // "Unexpected" is what `parameter_may_repeat` reads: a zero delta on a
639        // type whose own definition permits repeats is the second instance,
640        // which is the only encoding such an instance has.
641        if i > 0 && delta == 0 && !parameter_may_repeat(abs_key) {
642            return Err(CodecError::DuplicateParameter(abs_key));
643        }
644        prev_key = abs_key;
645
646        // Section 9.19: "All Message Parameters MUST be defined in the
647        // negotiated version of MOQT or negotiated via Setup Options. An
648        // endpoint that receives an unknown Message Parameter MUST close the
649        // session with INVALID_PARAMETER."
650        let encoding =
651            param_encoding(abs_key).ok_or(CodecError::UnknownMessageParameter(abs_key))?;
652
653        let value = decode_parameter_value(encoding, abs_key, buf)?;
654
655        params.push(KeyValuePair { key: VarInt::from_u64_moqt(abs_key), value });
656    }
657    check_authorization_tokens(&params)?;
658    check_location_filters(&params)?;
659    Ok(params)
660}
661
662/// Whether `bytes` is exactly the wire form of a Location — two consecutive
663/// varints and nothing after them.
664///
665/// `decode_parameters` builds this value by reading two varints and
666/// re-serialising them, so every value it produces satisfies this. A value
667/// built in memory need not, and the encode arm writes these bytes verbatim
668/// because a Location carries no length of its own. Without this check a
669/// caller could hand over one varint, or three, and the codec would put a
670/// frame on the wire that its own decoder answers with an error.
671fn is_location_value(bytes: &[u8]) -> bool {
672    let mut buf = bytes;
673    VarInt::decode_moqt::<Wire>(&mut buf).is_ok()
674        && VarInt::decode_moqt::<Wire>(&mut buf).is_ok()
675        && !buf.has_remaining()
676}
677
678/// Whether `bytes` is exactly the wire form of a Track Namespace, with
679/// nothing after it. The same reasoning as [`is_location_value`]: the value
680/// goes out verbatim, so it has to be something this draft can read back.
681fn is_track_namespace_value(bytes: &[u8]) -> bool {
682    let mut buf = bytes;
683    TrackNamespace::decode_allow_empty_moqt::<Wire>(&mut buf).is_ok() && !buf.has_remaining()
684}
685
686/// Encode a count-prefixed list of parameters with delta-encoded types.
687///
688/// Errors with [`CodecError::InvalidField`] on a uint8-valued parameter whose
689/// value [`decode_parameters`] would refuse, so the two directions accept the
690/// same set of frames.
691///
692/// The check is not a mirror added for tidiness. A uint8 parameter's value is
693/// written as one octet, and a value that does not fit one is otherwise
694/// truncated to its low byte: GROUP_ORDER 258 becomes the byte 0x02, which is
695/// Descending — a well-formed frame carrying a value the caller never asked
696/// for, and one no receiver could tell from a genuine Descending. Refusing is
697/// the only outcome that does not silently rewrite the message.
698///
699/// The two structure rules are here for a plainer reason. A value under a type
700/// that defines a structure and is not that structure — a Token, a filter — is
701/// one the receiver must close the session over, so writing it is not a way to
702/// send it; the sender's first sign of trouble would be the session going.
703fn encode_parameters(params: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
704    check_authorization_tokens(params)?;
705    check_location_filters(params)?;
706    VarInt::from_usize(params.len()).encode_moqt::<Wire>(buf);
707    let mut prev_key: u64 = 0;
708
709    for (i, p) in params.iter().enumerate() {
710        let abs_key = p.key.into_inner();
711        // The delta is a difference, so a descending pair wraps the subtraction
712        // into a nine-byte delta the peer resolves to an unrelated key, and a
713        // repeated type is a frame `decode_parameters` refuses. Both are
714        // refused here so the two directions accept the same set of frames.
715        let delta = abs_key
716            .checked_sub(prev_key)
717            .ok_or(CodecError::ParametersOutOfOrder(prev_key, abs_key))?;
718        if i > 0 && delta == 0 && !parameter_may_repeat(abs_key) {
719            return Err(CodecError::DuplicateParameter(abs_key));
720        }
721        prev_key = abs_key;
722        VarInt::from_u64_moqt(delta).encode_moqt::<Wire>(buf);
723
724        // Message Parameters are not Key-Value-Pairs and Section 9.19 gives
725        // them no value maximum; the message is "limited by
726        // MAX_CONTROL_MESSAGE_SIZE (Section 9.1.8)". A Length-prefixed value
727        // is bounded only by that.
728
729        let encoding = param_encoding(abs_key);
730        match (&p.value, encoding) {
731            (KvpValue::Varint(v), Some(ParamEncoding::Varint)) => {
732                v.encode_moqt::<Wire>(buf);
733            }
734            (KvpValue::Varint(v), Some(ParamEncoding::Uint8)) => {
735                let raw = v.into_inner();
736                let byte = u8::try_from(raw).map_err(|_| CodecError::InvalidField)?;
737                if !uint8_value_in_range(abs_key, byte) {
738                    return Err(CodecError::ParameterValueOutOfRange {
739                        key: abs_key,
740                        value: byte as u64,
741                    });
742                }
743                buf.put_u8(byte);
744            }
745            // These values are already stored in their own wire form — two
746            // varints for a Location, a field count and its fields for a Track
747            // Namespace, a type and its fields for a Location Filter — so they
748            // go out as they are. Adding a length here is the bug these arms
749            // exist to avoid.
750            (KvpValue::Bytes(b), Some(ParamEncoding::Location)) => {
751                if !is_location_value(b) {
752                    return Err(CodecError::InvalidField);
753                }
754                buf.put_slice(b);
755            }
756            (KvpValue::Bytes(b), Some(ParamEncoding::TrackNamespaceValue)) => {
757                if !is_track_namespace_value(b) {
758                    return Err(CodecError::InvalidField);
759                }
760                buf.put_slice(b);
761            }
762            // `check_location_filters` above has already held the value to
763            // its own type, which is the only check there is room for: the
764            // receiver finds the end of these bytes by reading the type, so a
765            // value whose fields disagree with its type desynchronises every
766            // parameter after it rather than failing on its own.
767            (KvpValue::Bytes(b), Some(ParamEncoding::LocationFilter)) => {
768                buf.put_slice(b);
769            }
770            // Held to its structure by `check_location_filters` above, for the
771            // same reason: the receiver finds its end by reading it.
772            (KvpValue::Bytes(b), Some(ParamEncoding::FillParameters)) => {
773                buf.put_slice(b);
774            }
775            (KvpValue::Bytes(b), Some(ParamEncoding::LengthPrefixed)) => {
776                VarInt::from_usize(b.len()).encode_moqt::<Wire>(buf);
777                buf.put_slice(b);
778            }
779            _ => {
780                // Fallback: encode as KVP even/odd
781                match &p.value {
782                    KvpValue::Varint(v) => v.encode_moqt::<Wire>(buf),
783                    KvpValue::Bytes(b) => {
784                        VarInt::from_usize(b.len()).encode_moqt::<Wire>(buf);
785                        buf.put_slice(b);
786                    }
787                }
788            }
789        }
790    }
791    Ok(())
792}
793
794/// Decode `bytes` as a run of Key-Value-Pairs, the shape of an Immutable
795/// Properties value (Section 10.7).
796pub(crate) fn decode_property_list(bytes: &[u8]) -> Result<Vec<KeyValuePair>, CodecError> {
797    let mut cursor = bytes;
798    decode_kvp_delta(&mut cursor)
799}
800
801/// Decode delta-encoded KVPs with even/odd convention (for setup options
802/// and track properties). Read until buffer is exhausted.
803fn decode_kvp_delta(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
804    let mut pairs = Vec::new();
805    let mut prev_key: u64 = 0;
806
807    while buf.has_remaining() {
808        let delta = VarInt::decode_moqt::<Wire>(buf)?.into_inner();
809        let abs_key = add_delta(prev_key, delta)?;
810        prev_key = abs_key;
811
812        let value = if abs_key.is_multiple_of(2) {
813            let v = VarInt::decode_moqt::<Wire>(buf)?;
814            KvpValue::Varint(v)
815        } else {
816            let len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
817            // Draft-23 Section 8.3: "The maximum length of a value is 2^16-1
818            // bytes. If an endpoint receives a length larger than the maximum,
819            // it MUST close the session with FIELD_LENGTH_EXCEEDED."
820            if len > MAX_KVP_VALUE_LEN {
821                return Err(KvpError::ValueTooLong(len).into());
822            }
823            let data = read_bytes(buf, len)?;
824            KvpValue::Bytes(data)
825        };
826
827        pairs.push(KeyValuePair { key: VarInt::from_u64_moqt(abs_key), value });
828    }
829    Ok(pairs)
830}
831
832/// Encode delta-encoded KVPs with even/odd convention.
833///
834/// Refuses a list that is not in ascending order by type, for the same reason
835/// [`encode_parameters`] does: the delta is a difference, and a descending pair
836/// wraps it into a nine-byte delta the peer resolves to an unrelated key.
837fn encode_kvp_delta(pairs: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
838    let mut prev_key: u64 = 0;
839    for p in pairs {
840        let abs_key = p.key.into_inner();
841        let delta = abs_key
842            .checked_sub(prev_key)
843            .ok_or(CodecError::ParametersOutOfOrder(prev_key, abs_key))?;
844        prev_key = abs_key;
845        VarInt::from_u64_moqt(delta).encode_moqt::<Wire>(buf);
846        match &p.value {
847            KvpValue::Varint(v) => v.encode_moqt::<Wire>(buf),
848            KvpValue::Bytes(b) => {
849                if b.len() > MAX_KVP_VALUE_LEN {
850                    return Err(KvpError::ValueTooLong(b.len()).into());
851                }
852                VarInt::from_usize(b.len()).encode_moqt::<Wire>(buf);
853                buf.put_slice(b);
854            }
855        }
856    }
857    Ok(())
858}
859
860/// Immutable Properties, Property Type 0xB.
861///
862/// Section 10.7: Immutable Properties are "a Track or Object Property that
863/// contains a sequence of Key-Value-Pairs (see Figure 4) that are themselves
864/// Track or Object Properties, respectively". The Type is odd, so its value is
865/// length-prefixed bytes, and those bytes are another delta-typed run starting
866/// from 0.
867const IMMUTABLE_PROPERTIES: u64 = 0x0B;
868
869/// Whether `value` is inside the range draft-23 allows for a Track Property
870/// type that restricts one.
871///
872/// Three types do, and each answers anything outside its range with
873/// MALFORMED_KEY_VALUE. DEFAULT_PUBLISHER_PRIORITY (0x0E), Section 10.4: "If an
874/// endpoint receives a value above 255, it MUST close the session with
875/// MALFORMED_KEY_VALUE." DEFAULT_PUBLISHER_GROUP_ORDER (0x22), Section 10.5:
876/// "The allowed values are Ascending (0x1) or Descending (0x2). If an endpoint
877/// receives a value outside this range, it MUST close the session with
878/// MALFORMED_KEY_VALUE." DYNAMIC_GROUPS (0x30), Section 10.6: "If an endpoint
879/// receives a value larger than 1, it MUST close the session with
880/// MALFORMED_KEY_VALUE."
881///
882/// The numbers belong to the Property registry, not the Message Parameter one:
883/// 0x22 is also GROUP_ORDER as a parameter.
884fn track_property_value_in_range(key: u64, value: u64) -> bool {
885    match key {
886        // DEFAULT_PUBLISHER_PRIORITY (0x0E)
887        0x0E => value <= 255,
888        // DEFAULT_PUBLISHER_GROUP_ORDER (0x22)
889        0x22 => value == 1 || value == 2,
890        // DYNAMIC_GROUPS (0x30)
891        0x30 => value <= 1,
892        _ => true,
893    }
894}
895
896/// Refuse a Track Property whose value falls outside the range its type allows,
897/// wherever in the list it is carried.
898///
899/// # Inside Immutable Properties as well as beside them
900///
901/// The list is walked one level down through Immutable Properties, whose
902/// contents Section 10.7 defines as properties themselves. The draft asks for
903/// this in as many words: "When looking for the value of a property, processors
904/// MUST search both the mutable properties and the contents of Immutable
905/// Properties." A check applied only to the outer list is one a peer opts out of
906/// by moving a pair inside the block, and the block is where an Original
907/// Publisher puts what a relay must not rewrite — which is where a track's group
908/// order and dynamic-group support belong.
909///
910/// Bytes under 0xB that do not parse as a Key-Value-Pair run are left alone
911/// rather than refused. Section 10.7 says relays "MAY decode and view the
912/// Properties in the Key-Value-Pairs", which is a permission and not a
913/// requirement, so a block this codec cannot read is carried to the caller
914/// intact instead of ending the session.
915fn check_track_property_values(properties: &[KeyValuePair]) -> Result<(), CodecError> {
916    for property in properties {
917        let key = property.key.into_inner();
918        match &property.value {
919            KvpValue::Varint(value) => {
920                let value = value.into_inner();
921                if !track_property_value_in_range(key, value) {
922                    return Err(CodecError::TrackPropertyValueOutOfRange { key, value });
923                }
924            }
925            KvpValue::Bytes(bytes) if key == IMMUTABLE_PROPERTIES => {
926                let mut inner = &bytes[..];
927                // A block that is not a Key-Value-Pair run is skipped rather
928                // than refused. See the note above: reading inside it is a
929                // permission, so one that cannot be read is carried.
930                //
931                // Skipped means this block and only this block. The rule the
932                // draft states here is about the block whose pairs will not
933                // parse, and says nothing about its neighbours; ending the
934                // whole walk would let a peer keep an out-of-range property
935                // from being looked at by putting an unparseable block in
936                // front of it.
937                if let Ok(nested) = decode_kvp_delta(&mut inner) {
938                    check_track_property_values(&nested)?;
939                }
940            }
941            KvpValue::Bytes(_) => {}
942        }
943    }
944    Ok(())
945}
946
947/// Decode the Track Properties that fill the tail of a control message.
948///
949/// [`decode_kvp_delta`] with the Property registry's value rules applied. The
950/// two are separate because that function also reads Setup Options, which are a
951/// third namespace numbering its entries independently of this one.
952fn decode_track_properties(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
953    let properties = decode_kvp_delta(buf)?;
954    check_track_property_values(&properties)?;
955    Ok(properties)
956}
957
958/// Encode a control message's Track Properties.
959///
960/// Held to the same value ranges as the decoder. A value this codec refuses to
961/// read is one it must not write: the peer that receives it is required to close
962/// the session, so the sender's first sign of trouble would be the session
963/// going.
964fn encode_track_properties(
965    properties: &[KeyValuePair],
966    buf: &mut impl BufMut,
967) -> Result<(), CodecError> {
968    check_track_property_values(properties)?;
969    encode_kvp_delta(properties, buf)
970}
971
972/// The Setup Option types this draft defines.
973///
974/// Section 9.1 assigns PATH, AUTHORIZATION TOKEN, MAX_AUTH_TOKEN_CACHE_SIZE, AUTHORITY,
975/// MAX_FILTER_RANGES, MOQT_IMPLEMENTATION, MAX_REQUEST_UPDATES and
976/// MAX_CONTROL_MESSAGE_SIZE.
977///
978/// The list exists for one rule and one direction. Section 9.1: "Receivers
979/// MUST allow duplicates of unknown Setup Options." A receiver may therefore
980/// refuse a repeat only of a type it can name, and an option outside this list
981/// is one an extension defined and this codec has no business closing a session
982/// over. Nothing else reads it - unknown options are still decoded and carried,
983/// as "Receivers MUST ignore unrecognized Setup Options" requires.
984const KNOWN_SETUP_OPTIONS: &[u64] =
985    &[0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, MAX_CONTROL_MESSAGE_SIZE_OPTION];
986
987/// The MAX_CONTROL_MESSAGE_SIZE Setup Option type, Section 9.1.8.
988pub const MAX_CONTROL_MESSAGE_SIZE_OPTION: u64 = 0x09;
989
990/// The MAX_CONTROL_MESSAGE_SIZE an endpoint uses for its peer until it has
991/// the peer's SETUP, and when the SETUP carries none.
992///
993/// Section 9.1.8: "The value is encoded as a variable-length integer and MUST
994/// be at least 65535. If not present, the default value is 65535. Until an
995/// endpoint receives the peer's SETUP, it uses the default value, including for
996/// SETUP itself."
997pub const DEFAULT_MAX_CONTROL_MESSAGE_SIZE: u64 = 65535;
998
999/// The value of a MAX_CONTROL_MESSAGE_SIZE option: the one `vi64` its bytes
1000/// hold.
1001///
1002/// Option Type 0x09 is odd, so Section 8.3 gives it a Length and "a sequence
1003/// of Length bytes", and Section 9.1.8 says "The value is encoded as a
1004/// variable-length integer". This codec reads the bytes as exactly one `vi64`;
1005/// anything else is a value that "does not match the serialization defined by
1006/// that Type", which Section 8.3 closes with MALFORMED_KEY_VALUE.
1007pub fn decode_max_control_message_size(value: &[u8]) -> Result<u64, CodecError> {
1008    const NOT_ONE_VARINT: &str = "its bytes are not exactly one variable-length integer";
1009    let mut cursor = value;
1010    let size =
1011        VarInt::decode_moqt::<Wire>(&mut cursor).map_err(|_| CodecError::KeyValueFormatting {
1012            key: MAX_CONTROL_MESSAGE_SIZE_OPTION,
1013            detail: NOT_ONE_VARINT,
1014        })?;
1015    if cursor.has_remaining() {
1016        return Err(CodecError::KeyValueFormatting {
1017            key: MAX_CONTROL_MESSAGE_SIZE_OPTION,
1018            detail: NOT_ONE_VARINT,
1019        });
1020    }
1021    Ok(size.into_inner())
1022}
1023
1024/// The bytes of a MAX_CONTROL_MESSAGE_SIZE option carrying `size`.
1025pub fn encode_max_control_message_size(size: u64) -> Vec<u8> {
1026    let mut value = Vec::new();
1027    VarInt::from_u64_moqt(size).encode_moqt::<Wire>(&mut value);
1028    value
1029}
1030
1031/// The MAX_CONTROL_MESSAGE_SIZE a SETUP's options advertise, or the default.
1032///
1033/// Section 9.1.8 states no receiver action for a value below 65535, so one is
1034/// returned as it arrived.
1035pub fn max_control_message_size(options: &[KeyValuePair]) -> Result<u64, CodecError> {
1036    for option in options {
1037        if option.key.into_inner() != MAX_CONTROL_MESSAGE_SIZE_OPTION {
1038            continue;
1039        }
1040        return match &option.value {
1041            KvpValue::Bytes(value) => decode_max_control_message_size(value),
1042            KvpValue::Varint(_) => Err(CodecError::KeyValueFormatting {
1043                key: MAX_CONTROL_MESSAGE_SIZE_OPTION,
1044                detail: "its value is a bare varint where the odd type requires a Length",
1045            }),
1046        };
1047    }
1048    Ok(DEFAULT_MAX_CONTROL_MESSAGE_SIZE)
1049}
1050
1051/// The one Setup Option whose definition allows more than one instance.
1052///
1053/// Section 9.1.4: "The AUTHORIZATION TOKEN Setup Option (Option Type 0x03)
1054/// is functionally equivalent to the AUTHORIZATION TOKEN message parameter...
1055/// The endpoint can specify one or more tokens in SETUP that the peer can use to
1056/// authorize MOQT session establishment." That is Section 9.1's "unless the
1057/// option definition explicitly allows multiple instances" carve-out, and it is
1058/// the only one on this draft.
1059const REPEATABLE_SETUP_OPTION: u64 = 0x03;
1060
1061/// Decode the Setup Options of a SETUP message.
1062///
1063/// Section 9.1: "Senders MUST NOT repeat the same Option Type in a message
1064/// unless the option definition explicitly allows multiple instances. Receivers
1065/// MUST allow duplicates of unknown Setup Options."
1066///
1067/// The second sentence is why this is not the mirror of
1068/// [`encode_setup_options`]: a repeat of a type this draft names is refused, and
1069/// a repeat of any other type is carried. Types ascend and are delta-encoded, so
1070/// a repeat is always a zero delta against the option before it.
1071fn decode_setup_options(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, CodecError> {
1072    let options = decode_kvp_delta(buf)?;
1073    for (i, option) in options.iter().enumerate() {
1074        let key = option.key.into_inner();
1075        if key == REPEATABLE_SETUP_OPTION || !KNOWN_SETUP_OPTIONS.contains(&key) {
1076            continue;
1077        }
1078        if options[..i].iter().any(|earlier| earlier.key == option.key) {
1079            return Err(CodecError::DuplicateParameter(key));
1080        }
1081    }
1082    check_authorization_tokens(&options)?;
1083    check_setup_token_aliases(&options)?;
1084    max_control_message_size(&options)?;
1085    Ok(options)
1086}
1087
1088/// Refuse a SETUP token that names an Alias with DELETE or USE_ALIAS.
1089///
1090/// SETUP is the first message an endpoint sends, so no Alias can be registered
1091/// when one arrives. Section 9.1.4: "If a server receives Alias Type DELETE
1092/// (0x0) or USE_ALIAS (0x2) in a SETUP message, it MUST close the session with
1093/// ROLE_VIOLATION." A client receiving one is referencing an Alias that is not
1094/// registered, which Section 8.9 answers with UNKNOWN_AUTH_TOKEN_ALIAS. Either
1095/// way the frame is refused, as [`CodecError::TokenAliasInSetup`].
1096fn check_setup_token_aliases(options: &[KeyValuePair]) -> Result<(), CodecError> {
1097    use crate::auth_token::TokenAliasType;
1098    for option in options {
1099        let key = option.key.into_inner();
1100        let KvpValue::Bytes(value) = &option.value else { continue };
1101        if key != AUTH_TOKEN_PARAMETER {
1102            continue;
1103        }
1104        let token = AuthorizationToken::decode_moqt::<Wire>(key, value).map_err(|_| {
1105            CodecError::MalformedAuthToken { key, detail: "the Token does not parse" }
1106        })?;
1107        if matches!(token.alias_type, TokenAliasType::Delete | TokenAliasType::UseAlias) {
1108            return Err(CodecError::TokenAliasInSetup { alias_type: token.alias_type.id() });
1109        }
1110    }
1111    Ok(())
1112}
1113
1114/// Encode the Setup Options of a SETUP message.
1115///
1116/// The sender's half of the same sentence, and it is the wider half: "Senders
1117/// MUST NOT repeat the same Option Type in a message" names no exception for
1118/// types the sender does not recognise, so every repeat is refused here except
1119/// the one the draft allows. A caller holding an option this codec has never
1120/// heard of still may not send it twice.
1121///
1122/// The token is in this namespace as well, and is held to its structure here for
1123/// the reason [`encode_parameters`] gives.
1124///
1125/// A MAX_CONTROL_MESSAGE_SIZE below 65535 is refused with
1126/// [`CodecError::InvalidField`]: Section 9.1.8 says the value "MUST be at
1127/// least 65535".
1128fn encode_setup_options(options: &[KeyValuePair], buf: &mut impl BufMut) -> Result<(), CodecError> {
1129    check_authorization_tokens(options)?;
1130    check_setup_token_aliases(options)?;
1131    if max_control_message_size(options)? < DEFAULT_MAX_CONTROL_MESSAGE_SIZE {
1132        return Err(CodecError::InvalidField);
1133    }
1134    for (i, option) in options.iter().enumerate() {
1135        if option.key.into_inner() == REPEATABLE_SETUP_OPTION {
1136            continue;
1137        }
1138        if options[..i].iter().any(|earlier| earlier.key == option.key) {
1139            return Err(CodecError::DuplicateParameter(option.key.into_inner()));
1140        }
1141    }
1142    encode_kvp_delta(options, buf)
1143}
1144
1145// ============================================================
1146// Message Types
1147// ============================================================
1148
1149/// The control message types draft-23 Section 9, Table 5 assigns.
1150///
1151/// Table 5 lists 0x18 as RESERVED, FETCH_OK in drafts up to 22: a FETCH is answered
1152/// with REQUEST_OK (Section 9.3), so 0x18 is an unknown type here.
1153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1154#[repr(u64)]
1155pub enum MessageType {
1156    RequestUpdate = 0x02,
1157    Subscribe = 0x03,
1158    SubscribeOk = 0x04,
1159    RequestError = 0x05,
1160    PublishNamespace = 0x06,
1161    /// REQUEST_OK (0x07). Draft-23 Section 1.5: "This document uses the
1162    /// shorthand PUBLISH_OK, FETCH_OK, REQUEST_UPDATE_OK, TRACK_STATUS_OK,
1163    /// SUBSCRIBE_NAMESPACE_OK, SUBSCRIBE_TRACKS_OK and PUBLISH_NAMESPACE_OK to
1164    /// refer to a REQUEST_OK sent in response to the corresponding request
1165    /// type."
1166    RequestOk = 0x07,
1167    Namespace = 0x08,
1168    PublishDone = 0x0B,
1169    TrackStatus = 0x0D,
1170    NamespaceDone = 0x0E,
1171    PublishSkipped = 0x0F,
1172    GoAway = 0x10,
1173    Fetch = 0x16,
1174    Publish = 0x1D,
1175    PublishStateNotify = 0x22,
1176    SubscribeNamespace = 0x50,
1177    SubscribeTracks = 0x51,
1178    Setup = 0x2F00,
1179}
1180
1181impl MessageType {
1182    pub fn from_id(id: u64) -> Option<Self> {
1183        match id {
1184            0x02 => Some(MessageType::RequestUpdate),
1185            0x03 => Some(MessageType::Subscribe),
1186            0x04 => Some(MessageType::SubscribeOk),
1187            0x05 => Some(MessageType::RequestError),
1188            0x06 => Some(MessageType::PublishNamespace),
1189            0x07 => Some(MessageType::RequestOk),
1190            0x08 => Some(MessageType::Namespace),
1191            0x0B => Some(MessageType::PublishDone),
1192            0x0D => Some(MessageType::TrackStatus),
1193            0x0E => Some(MessageType::NamespaceDone),
1194            0x0F => Some(MessageType::PublishSkipped),
1195            0x10 => Some(MessageType::GoAway),
1196            0x16 => Some(MessageType::Fetch),
1197            0x1D => Some(MessageType::Publish),
1198            0x22 => Some(MessageType::PublishStateNotify),
1199            0x50 => Some(MessageType::SubscribeNamespace),
1200            0x51 => Some(MessageType::SubscribeTracks),
1201            0x2F00 => Some(MessageType::Setup),
1202            _ => None,
1203        }
1204    }
1205
1206    pub fn id(&self) -> u64 {
1207        *self as u64
1208    }
1209
1210    /// This type's name in the shared vector corpus: the `message_type` its
1211    /// draft's `codec/messages/*.json` files carry, in `snake_case`.
1212    pub fn name(&self) -> &'static str {
1213        match self {
1214            MessageType::RequestUpdate => "request_update",
1215            MessageType::Subscribe => "subscribe",
1216            MessageType::SubscribeOk => "subscribe_ok",
1217            MessageType::RequestError => "request_error",
1218            MessageType::PublishNamespace => "publish_namespace",
1219            MessageType::RequestOk => "request_ok",
1220            MessageType::Namespace => "namespace",
1221            MessageType::PublishDone => "publish_done",
1222            MessageType::TrackStatus => "track_status",
1223            MessageType::NamespaceDone => "namespace_done",
1224            MessageType::PublishSkipped => "publish_skipped",
1225            MessageType::GoAway => "goaway",
1226            MessageType::Fetch => "fetch",
1227            MessageType::Publish => "publish",
1228            MessageType::PublishStateNotify => "publish_state_notify",
1229            MessageType::SubscribeNamespace => "subscribe_namespace",
1230            MessageType::SubscribeTracks => "subscribe_tracks",
1231            MessageType::Setup => "setup",
1232        }
1233    }
1234}
1235
1236// ============================================================
1237// Session Lifecycle Messages
1238// ============================================================
1239
1240/// Unified SETUP (0x2F00).
1241#[derive(Debug, Clone, PartialEq, Eq)]
1242pub struct Setup {
1243    pub options: Vec<KeyValuePair>,
1244}
1245
1246impl Setup {
1247    /// The MAX_CONTROL_MESSAGE_SIZE this SETUP advertises, or 65535 when it
1248    /// carries none (Section 9.1.8).
1249    pub fn max_control_message_size(&self) -> Result<u64, CodecError> {
1250        max_control_message_size(&self.options)
1251    }
1252}
1253
1254/// GOAWAY (0x10). There is no Request ID field, so the control-stream and
1255/// request-stream forms are identical on the wire.
1256#[derive(Debug, Clone, PartialEq, Eq)]
1257pub struct GoAway {
1258    pub new_session_uri: Vec<u8>,
1259    pub timeout: VarInt,
1260}
1261
1262// ============================================================
1263// Consolidated Response Messages
1264// ============================================================
1265
1266/// REQUEST_OK (0x07), the response to PUBLISH, FETCH, REQUEST_UPDATE,
1267/// TRACK_STATUS, SUBSCRIBE_NAMESPACE, SUBSCRIBE_TRACKS and PUBLISH_NAMESPACE
1268/// (Section 9.3).
1269///
1270/// Nothing in the frame says which request it answers, so the decoder holds
1271/// its parameters to the union of Section 9.3's lists and accepts Track
1272/// Properties. [`RequestOk::check_answers`] applies the rules for one request.
1273#[derive(Debug, Clone, PartialEq, Eq)]
1274pub struct RequestOk {
1275    pub parameters: Vec<KeyValuePair>,
1276    pub track_properties: Vec<KeyValuePair>,
1277}
1278
1279/// The request a [`RequestOk`] answers, named by Section 1.5's shorthand.
1280#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1281pub enum RequestOkKind {
1282    /// PUBLISH_OK.
1283    Publish,
1284    /// FETCH_OK.
1285    Fetch,
1286    /// REQUEST_UPDATE_OK.
1287    RequestUpdate,
1288    /// TRACK_STATUS_OK.
1289    TrackStatus,
1290    /// SUBSCRIBE_NAMESPACE_OK.
1291    SubscribeNamespace,
1292    /// SUBSCRIBE_TRACKS_OK.
1293    SubscribeTracks,
1294    /// PUBLISH_NAMESPACE_OK.
1295    PublishNamespace,
1296}
1297
1298impl RequestOkKind {
1299    /// Whether Section 9.3 lists Message Parameter `key` for this response.
1300    ///
1301    /// Section 9.3: "The parameters that can appear depend on the request being
1302    /// answered", then one list per response: EXPIRES and LARGEST_OBJECT for
1303    /// FETCH_OK, REQUEST_UPDATE_OK and TRACK_STATUS_OK, and EXPIRES alone for
1304    /// PUBLISH_OK, SUBSCRIBE_NAMESPACE_OK, SUBSCRIBE_TRACKS_OK and
1305    /// PUBLISH_NAMESPACE_OK.
1306    pub fn allows_parameter(self, key: u64) -> bool {
1307        const EXPIRES: u64 = 0x08;
1308        const LARGEST_OBJECT: u64 = 0x09;
1309        match self {
1310            RequestOkKind::Fetch | RequestOkKind::RequestUpdate | RequestOkKind::TrackStatus => {
1311                key == EXPIRES || key == LARGEST_OBJECT
1312            }
1313            RequestOkKind::Publish
1314            | RequestOkKind::SubscribeNamespace
1315            | RequestOkKind::SubscribeTracks
1316            | RequestOkKind::PublishNamespace => key == EXPIRES,
1317        }
1318    }
1319
1320    /// Whether this response may carry Track Properties.
1321    ///
1322    /// Section 9.3: "Track Properties are populated in TRACK_STATUS_OK and
1323    /// FETCH_OK; they are empty in PUBLISH_OK, REQUEST_UPDATE_OK,
1324    /// SUBSCRIBE_NAMESPACE_OK and PUBLISH_NAMESPACE_OK." SUBSCRIBE_TRACKS_OK
1325    /// is in neither list, so this does not refuse them there.
1326    pub fn allows_track_properties(self) -> bool {
1327        match self {
1328            RequestOkKind::Fetch | RequestOkKind::TrackStatus | RequestOkKind::SubscribeTracks => {
1329                true
1330            }
1331            RequestOkKind::Publish
1332            | RequestOkKind::RequestUpdate
1333            | RequestOkKind::SubscribeNamespace
1334            | RequestOkKind::PublishNamespace => false,
1335        }
1336    }
1337}
1338
1339impl RequestOk {
1340    /// Hold this REQUEST_OK to the rules for the response `kind`.
1341    ///
1342    /// A parameter the response's list does not name is
1343    /// [`CodecError::ParameterOutOfScope`] (Section 9.19.1, INVALID_PARAMETER),
1344    /// and Track Properties where the response must have none are
1345    /// [`CodecError::TrackPropertiesNotPermitted`] (Section 9.3,
1346    /// INVALID_FIELD).
1347    pub fn check_answers(&self, kind: RequestOkKind) -> Result<(), CodecError> {
1348        for parameter in &self.parameters {
1349            let key = parameter.key.into_inner();
1350            if !kind.allows_parameter(key) {
1351                return Err(CodecError::ParameterOutOfScope {
1352                    key,
1353                    message_type: MessageType::RequestOk.id(),
1354                });
1355            }
1356        }
1357        if !kind.allows_track_properties() && !self.track_properties.is_empty() {
1358            return Err(CodecError::TrackPropertiesNotPermitted);
1359        }
1360        Ok(())
1361    }
1362}
1363
1364/// The Error Detail types draft-23 Section 16.11, Table 19 assigns.
1365pub mod error_detail_types {
1366    /// REDIRECT (0x01), Section 9.4.2.1. Odd, so Length-prefixed.
1367    pub const REDIRECT: u64 = 0x01;
1368    /// UNSUPPORTED_PROPERTY (0x02), Section 9.4.2.2. Even, so a bare varint:
1369    /// "contains the Property Type (vi64) of a Mandatory Track Property".
1370    pub const UNSUPPORTED_PROPERTY: u64 = 0x02;
1371}
1372
1373/// The value of a REDIRECT Error Detail (Section 9.4.2.1).
1374///
1375/// ```text
1376/// REDIRECT Error Detail {
1377///   Type (vi64) = 0x01,
1378///   Length (vi64),
1379///   Connect URI Length (vi64),
1380///   Connect URI (..),
1381///   Track Namespace (..),
1382///   Track Name Length (vi64),
1383///   Track Name (..),
1384/// }
1385/// ```
1386///
1387/// The Track Name may be empty: "Track Name is not meaningful for
1388/// namespace-scoped requests (SUBSCRIBE_NAMESPACE, PUBLISH_NAMESPACE,
1389/// SUBSCRIBE_TRACKS) and MUST be empty". Which request it answers is session
1390/// state, so neither that rule nor the Connect URI's ROLE_VIOLATION is
1391/// checked here.
1392#[derive(Debug, Clone, PartialEq, Eq)]
1393pub struct Redirect {
1394    pub connect_uri: Vec<u8>,
1395    pub track_namespace: TrackNamespace,
1396    pub track_name: Vec<u8>,
1397}
1398
1399impl Redirect {
1400    /// Read a REDIRECT Error Detail's value.
1401    ///
1402    /// A value that is not the structure above is
1403    /// [`CodecError::MalformedErrorDetail`]. Section 8.3: "If a receiver
1404    /// understands a Type, and the following Value or Length/Value does not
1405    /// match the serialization defined by that Type, the receiver MUST close
1406    /// the session with MALFORMED_KEY_VALUE." The namespace's own rules
1407    /// (Section 8.7) keep their own errors.
1408    pub fn decode(value: &[u8]) -> Result<Self, CodecError> {
1409        const SHORT: &str = "its fields run past the end of the Error Detail";
1410        let malformed = |detail| CodecError::MalformedErrorDetail {
1411            detail_type: error_detail_types::REDIRECT,
1412            detail,
1413        };
1414        let mut buf = value;
1415        let uri_len =
1416            VarInt::decode_moqt::<Wire>(&mut buf).map_err(|_| malformed(SHORT))?.into_inner();
1417        let connect_uri = read_bytes(&mut buf, uri_len as usize).map_err(|_| malformed(SHORT))?;
1418        let track_namespace = TrackNamespace::decode_allow_empty_moqt::<Wire>(&mut buf)
1419            .map_err(|e| if e.is_incomplete() { malformed(SHORT) } else { e })?;
1420        let name_len =
1421            VarInt::decode_moqt::<Wire>(&mut buf).map_err(|_| malformed(SHORT))?.into_inner();
1422        let track_name = read_bytes(&mut buf, name_len as usize).map_err(|_| malformed(SHORT))?;
1423        if buf.has_remaining() {
1424            return Err(malformed("bytes follow its Track Name"));
1425        }
1426        check_full_track_name(&track_namespace, &track_name)?;
1427        Ok(Redirect { connect_uri, track_namespace, track_name })
1428    }
1429
1430    /// The value of a REDIRECT Error Detail carrying this redirect.
1431    pub fn encode(&self) -> Result<Vec<u8>, CodecError> {
1432        self.track_namespace.validate_moqt()?;
1433        check_full_track_name(&self.track_namespace, &self.track_name)?;
1434        let mut value = Vec::new();
1435        VarInt::from_usize(self.connect_uri.len()).encode_moqt::<Wire>(&mut value);
1436        value.put_slice(&self.connect_uri);
1437        self.track_namespace.encode_moqt::<Wire>(&mut value);
1438        VarInt::from_usize(self.track_name.len()).encode_moqt::<Wire>(&mut value);
1439        value.put_slice(&self.track_name);
1440        Ok(value)
1441    }
1442
1443    /// This redirect as a REDIRECT Error Detail.
1444    pub fn to_error_detail(&self) -> Result<KeyValuePair, CodecError> {
1445        Ok(KeyValuePair {
1446            key: VarInt::from_u64_moqt(error_detail_types::REDIRECT),
1447            value: KvpValue::Bytes(self.encode()?),
1448        })
1449    }
1450}
1451
1452/// REQUEST_ERROR (0x05), Section 9.4.1, Figure 10.
1453///
1454/// `error_details` are Key-Value-Pairs (Section 8.3) filling the rest of the
1455/// message: "Receivers MUST ignore unknown Error Detail types, and MUST ignore
1456/// a known Error Detail type that accompanies an Error Code it is not defined
1457/// for" (Section 9.4.2). They are carried in wire order, unknown ones included.
1458#[derive(Debug, Clone, PartialEq, Eq)]
1459pub struct RequestError {
1460    pub error_code: VarInt,
1461    pub retry_interval: VarInt,
1462    pub reason_phrase: Vec<u8>,
1463    pub error_details: Vec<KeyValuePair>,
1464}
1465
1466impl RequestError {
1467    /// The first REDIRECT Error Detail, decoded, if the error carries one.
1468    pub fn redirect(&self) -> Option<Result<Redirect, CodecError>> {
1469        self.error_details.iter().find_map(|detail| {
1470            (detail.key.into_inner() == error_detail_types::REDIRECT).then(|| match &detail.value {
1471                KvpValue::Bytes(value) => Redirect::decode(value),
1472                KvpValue::Varint(_) => Err(CodecError::MalformedErrorDetail {
1473                    detail_type: error_detail_types::REDIRECT,
1474                    detail: "its value is a bare varint where the odd type requires a Length",
1475                }),
1476            })
1477        })
1478    }
1479
1480    /// The Property Types named by UNSUPPORTED_PROPERTY Error Details, in wire
1481    /// order. Section 9.4.2.2: "Multiple instances of this type are allowed."
1482    pub fn unsupported_properties(&self) -> Vec<u64> {
1483        self.error_details
1484            .iter()
1485            .filter(|detail| detail.key.into_inner() == error_detail_types::UNSUPPORTED_PROPERTY)
1486            .filter_map(|detail| match &detail.value {
1487                KvpValue::Varint(v) => Some(v.into_inner()),
1488                KvpValue::Bytes(_) => None,
1489            })
1490            .collect()
1491    }
1492}
1493
1494/// REQUEST_ERROR error codes with dedicated meaning.
1495pub mod request_error_codes {
1496    /// UNAVAILABLE (0xA), Section 12.3: "The responder cannot fulfill this
1497    /// request at this time, but might be able to later".
1498    pub const UNAVAILABLE: u64 = 0x0A;
1499    /// A Mandatory Track Property the receiver does not understand. The
1500    /// UNSUPPORTED_PROPERTY Error Detail names it.
1501    pub const UNSUPPORTED_EXTENSION: u64 = 0x33;
1502    /// The REDIRECT Error Detail says where to retry.
1503    pub const REDIRECT: u64 = 0x34;
1504    /// SUBSCRIBE_TRACKS filter parameters conflict among too many subscribers
1505    /// to aggregate the subscription upstream.
1506    pub const CONFLICTING_FILTERS: u64 = 0x35;
1507    /// A Range Filter parameter is invalid or exceeds MAX_FILTER_RANGES.
1508    pub const INVALID_FILTER: u64 = 0x36;
1509}
1510
1511// ============================================================
1512// Subscribe Messages
1513// ============================================================
1514
1515#[derive(Debug, Clone, PartialEq, Eq)]
1516pub struct Subscribe {
1517    pub request_id: VarInt,
1518    pub track_namespace: TrackNamespace,
1519    pub track_name: Vec<u8>,
1520    pub parameters: Vec<KeyValuePair>,
1521}
1522
1523/// SUBSCRIBE_OK (0x04).
1524#[derive(Debug, Clone, PartialEq, Eq)]
1525pub struct SubscribeOk {
1526    pub track_alias: VarInt,
1527    pub parameters: Vec<KeyValuePair>,
1528    pub track_properties: Vec<KeyValuePair>,
1529}
1530
1531#[derive(Debug, Clone, PartialEq, Eq)]
1532pub struct RequestUpdate {
1533    pub request_id: VarInt,
1534    pub parameters: Vec<KeyValuePair>,
1535}
1536
1537// ============================================================
1538// Publish Messages
1539// ============================================================
1540
1541#[derive(Debug, Clone, PartialEq, Eq)]
1542pub struct Publish {
1543    pub request_id: VarInt,
1544    pub track_namespace: TrackNamespace,
1545    pub track_name: Vec<u8>,
1546    pub track_alias: VarInt,
1547    pub parameters: Vec<KeyValuePair>,
1548    pub track_properties: Vec<KeyValuePair>,
1549}
1550
1551/// PUBLISH_DONE (0x0B).
1552#[derive(Debug, Clone, PartialEq, Eq)]
1553pub struct PublishDone {
1554    /// The reason the publisher is ending the subscription.
1555    ///
1556    /// Not validated against the registry. Draft-23 Section 13: "Receipt of an
1557    /// unknown error code in any error context (Session Termination,
1558    /// REQUEST_ERROR, PUBLISH_DONE, or Data Stream Reset) MUST be treated as
1559    /// equivalent to INTERNAL_ERROR for that context. An endpoint MUST NOT
1560    /// close the session because it received an unknown error code in a
1561    /// REQUEST_ERROR or PUBLISH_DONE."
1562    pub status_code: VarInt,
1563    /// The number of streams the publisher opened for this subscription,
1564    /// including fill fetch streams (Section 9.9). See
1565    /// [`publish_done_codes::STREAM_COUNT_UNKNOWN`] for the sentinel.
1566    pub stream_count: VarInt,
1567    pub reason_phrase: Vec<u8>,
1568}
1569
1570/// Numeric values for the [`PublishDone`] fields.
1571pub mod publish_done_codes {
1572    /// TOO_FAR_BEHIND (0x5).
1573    pub const TOO_FAR_BEHIND: u64 = 0x05;
1574    /// EXPIRED (0x6).
1575    pub const EXPIRED: u64 = 0x06;
1576    /// EXPIRED_AUTH_TOKEN (0x7). Section 9.9: "A publisher that ends a
1577    /// subscription because the authorization token that authorized it has
1578    /// expired SHOULD send PUBLISH_DONE with status code EXPIRED_AUTH_TOKEN."
1579    pub const EXPIRED_AUTH_TOKEN: u64 = 0x07;
1580
1581    /// The value [`super::PublishDone::stream_count`] carries when the
1582    /// publisher cannot state an exact count.
1583    ///
1584    /// Section 9.9: "If the publisher is unable to set Stream Count to the
1585    /// exact number of streams opened for the subscription, it MUST set
1586    /// Stream Count to 2^64 - 1." The sentinel is indistinguishable from an
1587    /// exact count of `2^64 - 1`.
1588    pub const STREAM_COUNT_UNKNOWN: u64 = u64::MAX;
1589}
1590
1591// ============================================================
1592// Publish Namespace Messages
1593// ============================================================
1594
1595#[derive(Debug, Clone, PartialEq, Eq)]
1596pub struct PublishNamespace {
1597    pub request_id: VarInt,
1598    pub track_namespace: TrackNamespace,
1599    pub parameters: Vec<KeyValuePair>,
1600}
1601
1602// ============================================================
1603// Namespace Messages
1604// ============================================================
1605
1606/// NAMESPACE (0x08), Section 9.15, Figure 20: a Track Namespace Suffix, then a
1607/// parameter block.
1608///
1609/// No Message Parameter definition names NAMESPACE, so under Section 9.19.1
1610/// any parameter here is out of scope; the block is read and every entry in it
1611/// refused.
1612#[derive(Debug, Clone, PartialEq, Eq)]
1613pub struct Namespace {
1614    pub namespace_suffix: TrackNamespace,
1615    pub parameters: Vec<KeyValuePair>,
1616}
1617
1618#[derive(Debug, Clone, PartialEq, Eq)]
1619pub struct NamespaceDone {
1620    pub namespace_suffix: TrackNamespace,
1621}
1622
1623// ============================================================
1624// Subscribe Namespace / Tracks Messages
1625// ============================================================
1626
1627/// SUBSCRIBE_NAMESPACE (0x50). Subscribes to NAMESPACE / NAMESPACE_DONE
1628/// advertisements for namespaces matching `namespace_prefix`.
1629#[derive(Debug, Clone, PartialEq, Eq)]
1630pub struct SubscribeNamespace {
1631    pub request_id: VarInt,
1632    pub namespace_prefix: TrackNamespace,
1633    pub parameters: Vec<KeyValuePair>,
1634}
1635
1636/// SUBSCRIBE_TRACKS (0x51). Subscribes to PUBLISH messages for tracks whose
1637/// namespace matches `namespace_prefix`.
1638#[derive(Debug, Clone, PartialEq, Eq)]
1639pub struct SubscribeTracks {
1640    pub request_id: VarInt,
1641    pub namespace_prefix: TrackNamespace,
1642    pub parameters: Vec<KeyValuePair>,
1643}
1644
1645// ============================================================
1646// Track Status Messages
1647// ============================================================
1648
1649#[derive(Debug, Clone, PartialEq, Eq)]
1650pub struct TrackStatus {
1651    pub request_id: VarInt,
1652    pub track_namespace: TrackNamespace,
1653    pub track_name: Vec<u8>,
1654    pub parameters: Vec<KeyValuePair>,
1655}
1656
1657// ============================================================
1658// Fetch Messages
1659// ============================================================
1660
1661/// FETCH (0x16), Section 9.11, Figure 17.
1662///
1663/// ```text
1664/// FETCH Message {
1665///   Type (vi64) = 0x16,
1666///   Length (vi64),
1667///   Request ID (vi64),
1668///   Track Namespace (..),
1669///   Track Name Length (vi64),
1670///   Track Name (..),
1671///   Number of Parameters (vi64),
1672///   Parameters (..) ...
1673/// }
1674/// ```
1675///
1676/// The range travels in the `LOCATION_FILTER` parameter. Section 3.2: "If the
1677/// Location filter is relative (see Section 9.19.9), the publisher MUST return
1678/// REQUEST_ERROR with error code INVALID_RANGE." That is a reply rather than a
1679/// close, so every Location Filter Type decodes here.
1680#[derive(Debug, Clone, PartialEq, Eq)]
1681pub struct Fetch {
1682    pub request_id: VarInt,
1683    pub track_namespace: TrackNamespace,
1684    pub track_name: Vec<u8>,
1685    pub parameters: Vec<KeyValuePair>,
1686}
1687
1688// ============================================================
1689// Publish State Notify
1690// ============================================================
1691
1692/// PUBLISH_STATE_NOTIFY (0x22), Section 9.10, Figure 16.
1693///
1694/// No Request ID: the subscription's request stream identifies it. Section
1695/// 9.10's rules about who sends it and on which stream ("An endpoint that
1696/// receives a PUBLISH_STATE_NOTIFY for any other request type MUST close the
1697/// session with UNEXPECTED_MESSAGE. A publisher that receives a
1698/// PUBLISH_STATE_NOTIFY MUST close the session with ROLE_VIOLATION.") are
1699/// session state and belong to the caller.
1700#[derive(Debug, Clone, PartialEq, Eq)]
1701pub struct PublishStateNotify {
1702    pub parameters: Vec<KeyValuePair>,
1703}
1704
1705// ============================================================
1706// Publish Skipped
1707// ============================================================
1708
1709/// PUBLISH_SKIPPED (0x0F): a track namespace suffix, then a track name.
1710#[derive(Debug, Clone, PartialEq, Eq)]
1711pub struct PublishSkipped {
1712    pub namespace_suffix: TrackNamespace,
1713    pub track_name: Vec<u8>,
1714}
1715
1716// ============================================================
1717// Unified Message Enum
1718// ============================================================
1719
1720#[derive(Debug, Clone, PartialEq, Eq)]
1721pub enum ControlMessage {
1722    Setup(Setup),
1723    GoAway(GoAway),
1724    RequestOk(RequestOk),
1725    RequestError(RequestError),
1726    Subscribe(Subscribe),
1727    SubscribeOk(SubscribeOk),
1728    RequestUpdate(RequestUpdate),
1729    Publish(Publish),
1730    PublishStateNotify(PublishStateNotify),
1731    PublishDone(PublishDone),
1732    PublishNamespace(PublishNamespace),
1733    Namespace(Namespace),
1734    NamespaceDone(NamespaceDone),
1735    SubscribeNamespace(SubscribeNamespace),
1736    SubscribeTracks(SubscribeTracks),
1737    TrackStatus(TrackStatus),
1738    Fetch(Fetch),
1739    PublishSkipped(PublishSkipped),
1740}
1741
1742/// Hold a REQUEST_ERROR's Error Details to its Error Code.
1743///
1744/// Section 9.4.2.1: the REDIRECT Error Detail "accompanies Error Code REDIRECT
1745/// and MUST be present when the Error Code is REDIRECT. An endpoint that
1746/// receives a REQUEST_ERROR with Error Code REDIRECT and no REDIRECT Error
1747/// Detail MUST close the session with MALFORMED_MESSAGE." Under that code each
1748/// REDIRECT detail is also held to its structure. Under any other code a
1749/// REDIRECT detail is one the receiver "MUST ignore", so it is carried
1750/// unread.
1751///
1752/// Section 9.4.2 states no receiver action for a repeated REDIRECT detail, so
1753/// the decoder accepts one; [`check_error_details_to_send`] refuses it.
1754fn check_error_details(m: &RequestError) -> Result<(), CodecError> {
1755    if m.error_code.into_inner() != request_error_codes::REDIRECT {
1756        return Ok(());
1757    }
1758    let mut found = false;
1759    for detail in &m.error_details {
1760        if detail.key.into_inner() != error_detail_types::REDIRECT {
1761            continue;
1762        }
1763        found = true;
1764        match &detail.value {
1765            KvpValue::Bytes(value) => {
1766                Redirect::decode(value)?;
1767            }
1768            KvpValue::Varint(_) => {
1769                return Err(CodecError::MalformedErrorDetail {
1770                    detail_type: error_detail_types::REDIRECT,
1771                    detail: "its value is a bare varint where the odd type requires a Length",
1772                });
1773            }
1774        }
1775    }
1776    if !found {
1777        return Err(CodecError::MissingErrorDetail {
1778            error_code: request_error_codes::REDIRECT,
1779            detail_type: error_detail_types::REDIRECT,
1780        });
1781    }
1782    Ok(())
1783}
1784
1785/// The sender's half of [`check_error_details`], plus Section 9.4.2:
1786/// "Senders MUST NOT repeat the same Error Detail type in a message unless
1787/// the type's definition explicitly allows multiple instances." Only
1788/// UNSUPPORTED_PROPERTY allows them, and a type this draft does not define is
1789/// the caller's to repeat or not.
1790fn check_error_details_to_send(m: &RequestError) -> Result<(), CodecError> {
1791    check_error_details(m)?;
1792    let redirects = m
1793        .error_details
1794        .iter()
1795        .filter(|detail| detail.key.into_inner() == error_detail_types::REDIRECT)
1796        .count();
1797    if redirects > 1 {
1798        return Err(CodecError::DuplicateParameter(error_detail_types::REDIRECT));
1799    }
1800    Ok(())
1801}
1802
1803/// Whether draft-23 lets Message Parameter `key` appear in `message`.
1804///
1805/// Section 9.19.1: "Each Message Parameter definition indicates the message
1806/// types in which it can appear, and each control message definition lists the
1807/// parameters it allows. If a parameter appears in some other type of message,
1808/// the receiving endpoint MUST close the session with INVALID_PARAMETER." One
1809/// arm per entry in the Message Parameters registry (Section 16.7), carrying the
1810/// message types that entry's own definition names. The lists in the message
1811/// definitions say the same thing from the other side.
1812///
1813/// REQUEST_OK and REQUEST_UPDATE list their parameters per kind of request
1814/// (Section 9.3 and Section 9.5), and the request is session state, so each is
1815/// held to the union of its lists here. [`RequestOk::check_answers`] narrows a
1816/// REQUEST_OK to one list.
1817///
1818/// No definition names NAMESPACE, so every parameter is out of scope there.
1819///
1820/// The table decides scope only. A type this draft does not define has no scope
1821/// to be outside of and is answered by [`CodecError::UnknownMessageParameter`],
1822/// which is why the final arm carries rather than refuses.
1823pub fn parameter_in_scope(key: u64, message: MessageType) -> bool {
1824    use MessageType as M;
1825    match key {
1826        // Section 9.19.4 OBJECT_DELIVERY_TIMEOUT and Section 9.19.3
1827        // SUBGROUP_DELIVERY_TIMEOUT: "It MAY appear in a SUBSCRIBE, PUBLISH,
1828        // SUBSCRIBE_TRACKS, or REQUEST_UPDATE (for a subscription) message."
1829        0x02 | 0x06 => {
1830            matches!(message, M::Subscribe | M::Publish | M::SubscribeTracks | M::RequestUpdate)
1831        }
1832        // Section 9.19.2 AUTHORIZATION TOKEN: "It MAY appear in a PUBLISH,
1833        // SUBSCRIBE, REQUEST_UPDATE, SUBSCRIBE_NAMESPACE, SUBSCRIBE_TRACKS,
1834        // PUBLISH_NAMESPACE, TRACK_STATUS or FETCH message."
1835        0x03 => matches!(
1836            message,
1837            M::Publish
1838                | M::Subscribe
1839                | M::RequestUpdate
1840                | M::SubscribeNamespace
1841                | M::SubscribeTracks
1842                | M::PublishNamespace
1843                | M::TrackStatus
1844                | M::Fetch
1845        ),
1846        // Section 9.19.6 RENDEZVOUS TIMEOUT: "It MAY appear in a SUBSCRIBE
1847        // message."
1848        0x04 => matches!(message, M::Subscribe),
1849        // Section 9.19.16 EXPIRES: "It MAY appear in PUBLISH, SUBSCRIBE_OK,
1850        // FETCH_OK, or any REQUEST_OK."
1851        0x08 => matches!(message, M::Publish | M::SubscribeOk | M::RequestOk),
1852        // Section 9.19.17 LARGEST OBJECT: "It MAY appear in SUBSCRIBE_OK,
1853        // PUBLISH, REQUEST_UPDATE_OK, TRACK_STATUS_OK, FETCH_OK, or
1854        // PUBLISH_STATE_NOTIFY."
1855        0x09 => {
1856            matches!(message, M::SubscribeOk | M::Publish | M::RequestOk | M::PublishStateNotify)
1857        }
1858        // Section 9.19.5 FILL TIMEOUT: "It MAY appear in a FETCH message, or
1859        // inside a FILL_PARAMETERS parameter". The nested half is Table 7's.
1860        0x0A => matches!(message, M::Fetch),
1861        // Section 9.19.18 PAUSED: "It MAY appear in SUBSCRIBE, REQUEST_UPDATE
1862        // (for a subscription or a SUBSCRIBE_TRACKS request), PUBLISH,
1863        // SUBSCRIBE_TRACKS and PUBLISH_STATE_NOTIFY."
1864        0x11 => matches!(
1865            message,
1866            M::Subscribe
1867                | M::RequestUpdate
1868                | M::Publish
1869                | M::SubscribeTracks
1870                | M::PublishStateNotify
1871        ),
1872        // Section 9.19.7 SUBSCRIBER PRIORITY: "It MAY appear in a SUBSCRIBE,
1873        // PUBLISH, SUBSCRIBE_TRACKS, FETCH, or REQUEST_UPDATE (for a
1874        // subscription or FETCH), or inside a FILL_PARAMETERS parameter".
1875        0x20 => matches!(
1876            message,
1877            M::Subscribe | M::Publish | M::SubscribeTracks | M::Fetch | M::RequestUpdate
1878        ),
1879        // Section 9.19.9: "The LOCATION_FILTER parameter (Parameter Type 0x21)
1880        // MAY appear in a FETCH, SUBSCRIBE, PUBLISH, SUBSCRIBE_TRACKS,
1881        // REQUEST_UPDATE (for a subscription) or PUBLISH_STATE_NOTIFY message,
1882        // or inside a FILL_PARAMETERS parameter".
1883        0x21 => matches!(
1884            message,
1885            M::Fetch
1886                | M::Subscribe
1887                | M::Publish
1888                | M::SubscribeTracks
1889                | M::RequestUpdate
1890                | M::PublishStateNotify
1891        ),
1892        // Section 9.19.8 GROUP ORDER: "It MAY appear in a SUBSCRIBE, PUBLISH,
1893        // SUBSCRIBE_TRACKS, or FETCH, or inside a FILL_PARAMETERS parameter".
1894        0x22 => matches!(message, M::Subscribe | M::Publish | M::SubscribeTracks | M::Fetch),
1895        // Section 9.19.15: "The FILL_PARAMETERS parameter (Parameter Type
1896        // 0x23) MAY appear in a SUBSCRIBE, SUBSCRIBE_TRACKS, PUBLISH, or
1897        // REQUEST_UPDATE (for a subscription) message."
1898        0x23 => {
1899            matches!(message, M::Subscribe | M::SubscribeTracks | M::Publish | M::RequestUpdate)
1900        }
1901        // Section 3.3.2: "All other filter parameters MAY appear multiple times
1902        // in a FETCH, SUBSCRIBE, SUBSCRIBE_TRACKS, or REQUEST_UPDATE (on a
1903        // subscription, from the subscriber only) message." SUBGROUP_FILTER
1904        // (Section 9.19.10), OBJECTID_FILTER (Section 9.19.11), PRIORITY_FILTER
1905        // (Section 9.19.12) and OBJECT_PROPERTY_FILTER (Section 9.19.13).
1906        0x25..=0x28 => {
1907            matches!(message, M::Fetch | M::Subscribe | M::SubscribeTracks | M::RequestUpdate)
1908        }
1909        // Section 3.3.2, of TRACK_PROPERTY_FILTER (Section 9.19.14): "The Track
1910        // Property filter parameter MAY appear multiple times in a
1911        // SUBSCRIBE_TRACKS message or REQUEST_UPDATE for it."
1912        0x29 => matches!(message, M::SubscribeTracks | M::RequestUpdate),
1913        // Section 9.19.19 NEW GROUP REQUEST: "It MAY appear in SUBSCRIBE or
1914        // REQUEST_UPDATE for a subscription."
1915        0x32 => matches!(message, M::Subscribe | M::RequestUpdate),
1916        // Section 9.19.20 TRACK_NAMESPACE_PREFIX: "It MAY appear in
1917        // REQUEST_UPDATE for a SUBSCRIBE_NAMESPACE or SUBSCRIBE_TRACKS
1918        // request."
1919        0x34 => matches!(message, M::RequestUpdate),
1920        // Section 9.19.22 INCLUDE_PROPERTIES: "It MAY appear in SUBSCRIBE,
1921        // TRACK_STATUS, FETCH or SUBSCRIBE_TRACKS."
1922        0x35 => matches!(message, M::Subscribe | M::TrackStatus | M::Fetch | M::SubscribeTracks),
1923        // Section 9.19.21 SUBSCRIBE_TRACKS_ID: "It appears only in a PUBLISH
1924        // sent as a result of a SUBSCRIBE_TRACKS". Whether a PUBLISH was sent
1925        // for one is session state.
1926        0x36 => matches!(message, M::Publish),
1927        _ => true,
1928    }
1929}
1930
1931/// Refuse a message carrying a Message Parameter its own definition does not
1932/// place there (Section 9.19.1).
1933///
1934/// Applied on both sides. A parameter outside its scope is one the peer must
1935/// close the session over, so writing one is a way to end a session rather than
1936/// a way to ask for anything.
1937fn check_parameter_scope(message: &ControlMessage) -> Result<(), CodecError> {
1938    let parameters = match message {
1939        ControlMessage::RequestOk(m) => &m.parameters,
1940        ControlMessage::Subscribe(m) => &m.parameters,
1941        ControlMessage::SubscribeOk(m) => &m.parameters,
1942        ControlMessage::RequestUpdate(m) => &m.parameters,
1943        ControlMessage::Publish(m) => &m.parameters,
1944        ControlMessage::PublishStateNotify(m) => &m.parameters,
1945        ControlMessage::PublishNamespace(m) => &m.parameters,
1946        ControlMessage::Namespace(m) => &m.parameters,
1947        ControlMessage::SubscribeNamespace(m) => &m.parameters,
1948        ControlMessage::SubscribeTracks(m) => &m.parameters,
1949        ControlMessage::TrackStatus(m) => &m.parameters,
1950        ControlMessage::Fetch(m) => &m.parameters,
1951        // No Message Parameters field. Section 9.19.1: "Note that since Setup
1952        // Options use a separate namespace, it is impossible for Message
1953        // Parameters to appear in Setup messages."
1954        ControlMessage::Setup(_)
1955        | ControlMessage::GoAway(_)
1956        | ControlMessage::RequestError(_)
1957        | ControlMessage::PublishDone(_)
1958        | ControlMessage::NamespaceDone(_)
1959        | ControlMessage::PublishSkipped(_) => return Ok(()),
1960    };
1961
1962    let message_type = message.message_type();
1963    for parameter in parameters {
1964        let key = parameter.key.into_inner();
1965        if !parameter_in_scope(key, message_type) {
1966            return Err(CodecError::ParameterOutOfScope { key, message_type: message_type.id() });
1967        }
1968    }
1969    Ok(())
1970}
1971
1972impl ControlMessage {
1973    /// Encode under the default MAX_CONTROL_MESSAGE_SIZE of 65535, which is the
1974    /// limit until the peer's SETUP arrives (Section 9.1.8).
1975    pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
1976        self.encode_with_limit(buf, DEFAULT_MAX_CONTROL_MESSAGE_SIZE)
1977    }
1978
1979    /// Encode for a peer whose MAX_CONTROL_MESSAGE_SIZE is `limit`.
1980    ///
1981    /// Section 9: "An endpoint MUST NOT send a control message with a length
1982    /// larger than the peer's MAX_CONTROL_MESSAGE_SIZE (Section 9.1.8)." The
1983    /// length is the Message Length field, the body alone.
1984    pub fn encode_with_limit(&self, buf: &mut impl BufMut, limit: u64) -> Result<(), CodecError> {
1985        if let ControlMessage::RequestError(m) = self {
1986            check_error_details_to_send(m)?;
1987        }
1988        check_parameter_scope(self)?;
1989        let mut body = Vec::with_capacity(256);
1990        self.encode_body(&mut body)?;
1991
1992        if body.len() as u64 > limit {
1993            return Err(CodecError::ControlMessageExceedsLimit {
1994                length: body.len() as u64,
1995                limit,
1996            });
1997        }
1998
1999        VarInt::from_u64_moqt(self.message_type().id()).encode_moqt::<Wire>(buf);
2000        // Section 9, Figure 6: "Message Length (vi64)".
2001        VarInt::from_usize(body.len()).encode_moqt::<Wire>(buf);
2002        buf.put_slice(&body);
2003        Ok(())
2004    }
2005
2006    /// Decode under the default MAX_CONTROL_MESSAGE_SIZE of 65535: the limit
2007    /// of an endpoint that advertised none (Section 9.1.8).
2008    pub fn decode(buf: &mut impl Buf) -> Result<Self, CodecError> {
2009        Self::decode_with_limit(buf, DEFAULT_MAX_CONTROL_MESSAGE_SIZE)
2010    }
2011
2012    /// Decode as an endpoint whose own MAX_CONTROL_MESSAGE_SIZE is `limit`.
2013    ///
2014    /// Section 9: "If an endpoint receives a control message with a length
2015    /// larger than its MAX_CONTROL_MESSAGE_SIZE, it MUST close the session with
2016    /// FIELD_LENGTH_EXCEEDED." The Length is checked before the body is
2017    /// waited for, so an oversized message is refused as soon as its Length
2018    /// has arrived.
2019    pub fn decode_with_limit(buf: &mut impl Buf, limit: u64) -> Result<Self, CodecError> {
2020        let type_id = VarInt::decode_moqt::<Wire>(buf)?.into_inner();
2021        let msg_type =
2022            MessageType::from_id(type_id).ok_or(CodecError::UnknownMessageType(type_id))?;
2023        let declared = VarInt::decode_moqt::<Wire>(buf)?.into_inner();
2024        if declared > limit {
2025            return Err(CodecError::ControlMessageExceedsLimit { length: declared, limit });
2026        }
2027        let body_len = declared as usize;
2028        if buf.remaining() < body_len {
2029            return Err(CodecError::UnexpectedEnd);
2030        }
2031        let body_bytes = buf.copy_to_bytes(body_len);
2032        let mut body = &body_bytes[..];
2033        let msg = match Self::decode_body(msg_type, &mut body) {
2034            Ok(msg) => msg,
2035            // The fields wanted more bytes than the Length gives. The buffer
2036            // is bounded by that Length, so nothing more can arrive.
2037            Err(
2038                CodecError::UnexpectedEnd
2039                | CodecError::Kvp(crate::kvp::KvpError::UnexpectedEnd)
2040                | CodecError::Kvp(crate::kvp::KvpError::VarInt(
2041                    crate::varint::VarIntError::UnexpectedEnd,
2042                ))
2043                | CodecError::VarInt(crate::varint::VarIntError::UnexpectedEnd),
2044            ) => {
2045                return Err(CodecError::ControlMessageLengthMismatch {
2046                    declared: body_len,
2047                    detail: "its fields need more bytes than its Length gives",
2048                });
2049            }
2050            Err(e) => return Err(e),
2051        };
2052        check_parameter_scope(&msg)?;
2053        // Draft-23 Section 9: "If the length does not match the length of the
2054        // Message Body, the receiver MUST close the session with
2055        // MALFORMED_MESSAGE."
2056        if body.has_remaining() {
2057            return Err(CodecError::ControlMessageLengthMismatch {
2058                declared: body_len,
2059                detail: "its fields left bytes unread",
2060            });
2061        }
2062        Ok(msg)
2063    }
2064
2065    fn encode_body(&self, buf: &mut impl BufMut) -> Result<(), CodecError> {
2066        match self {
2067            ControlMessage::Setup(m) => {
2068                encode_setup_options(&m.options, buf)?;
2069            }
2070            ControlMessage::GoAway(m) => {
2071                if m.new_session_uri.len() > MAX_GOAWAY_URI_LENGTH {
2072                    return Err(CodecError::GoAwayUriTooLong);
2073                }
2074                VarInt::from_usize(m.new_session_uri.len()).encode_moqt::<Wire>(buf);
2075                buf.put_slice(&m.new_session_uri);
2076                m.timeout.encode_moqt::<Wire>(buf);
2077            }
2078            ControlMessage::RequestOk(m) => {
2079                encode_parameters(&m.parameters, buf)?;
2080                encode_track_properties(&m.track_properties, buf)?;
2081            }
2082            ControlMessage::RequestError(m) => {
2083                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
2084                    return Err(CodecError::ReasonPhraseTooLong);
2085                }
2086                m.error_code.encode_moqt::<Wire>(buf);
2087                m.retry_interval.encode_moqt::<Wire>(buf);
2088                VarInt::from_usize(m.reason_phrase.len()).encode_moqt::<Wire>(buf);
2089                buf.put_slice(&m.reason_phrase);
2090                encode_kvp_delta(&m.error_details, buf)?;
2091            }
2092            ControlMessage::Subscribe(m) => {
2093                m.track_namespace.validate_moqt()?;
2094                check_track_name(&m.track_name)?;
2095                check_full_track_name(&m.track_namespace, &m.track_name)?;
2096                m.request_id.encode_moqt::<Wire>(buf);
2097                m.track_namespace.encode_moqt::<Wire>(buf);
2098                VarInt::from_usize(m.track_name.len()).encode_moqt::<Wire>(buf);
2099                buf.put_slice(&m.track_name);
2100                encode_parameters(&m.parameters, buf)?;
2101            }
2102            ControlMessage::SubscribeOk(m) => {
2103                m.track_alias.encode_moqt::<Wire>(buf);
2104                encode_parameters(&m.parameters, buf)?;
2105                encode_track_properties(&m.track_properties, buf)?;
2106            }
2107            ControlMessage::RequestUpdate(m) => {
2108                m.request_id.encode_moqt::<Wire>(buf);
2109                encode_parameters(&m.parameters, buf)?;
2110            }
2111            ControlMessage::Publish(m) => {
2112                m.track_namespace.validate_moqt()?;
2113                check_track_name(&m.track_name)?;
2114                check_full_track_name(&m.track_namespace, &m.track_name)?;
2115                m.request_id.encode_moqt::<Wire>(buf);
2116                m.track_namespace.encode_moqt::<Wire>(buf);
2117                VarInt::from_usize(m.track_name.len()).encode_moqt::<Wire>(buf);
2118                buf.put_slice(&m.track_name);
2119                m.track_alias.encode_moqt::<Wire>(buf);
2120                encode_parameters(&m.parameters, buf)?;
2121                encode_track_properties(&m.track_properties, buf)?;
2122            }
2123            ControlMessage::PublishStateNotify(m) => {
2124                encode_parameters(&m.parameters, buf)?;
2125            }
2126            ControlMessage::PublishDone(m) => {
2127                if m.reason_phrase.len() > MAX_REASON_PHRASE_LENGTH {
2128                    return Err(CodecError::ReasonPhraseTooLong);
2129                }
2130                m.status_code.encode_moqt::<Wire>(buf);
2131                m.stream_count.encode_moqt::<Wire>(buf);
2132                VarInt::from_usize(m.reason_phrase.len()).encode_moqt::<Wire>(buf);
2133                buf.put_slice(&m.reason_phrase);
2134            }
2135            ControlMessage::PublishNamespace(m) => {
2136                m.track_namespace.validate_moqt()?;
2137                m.request_id.encode_moqt::<Wire>(buf);
2138                m.track_namespace.encode_moqt::<Wire>(buf);
2139                encode_parameters(&m.parameters, buf)?;
2140            }
2141            ControlMessage::Namespace(m) => {
2142                m.namespace_suffix.validate_moqt()?;
2143                m.namespace_suffix.encode_moqt::<Wire>(buf);
2144                encode_parameters(&m.parameters, buf)?;
2145            }
2146            ControlMessage::NamespaceDone(m) => {
2147                m.namespace_suffix.validate_moqt()?;
2148                m.namespace_suffix.encode_moqt::<Wire>(buf);
2149            }
2150            ControlMessage::SubscribeNamespace(m) => {
2151                m.namespace_prefix.validate_moqt()?;
2152                m.request_id.encode_moqt::<Wire>(buf);
2153                m.namespace_prefix.encode_moqt::<Wire>(buf);
2154                encode_parameters(&m.parameters, buf)?;
2155            }
2156            ControlMessage::SubscribeTracks(m) => {
2157                m.namespace_prefix.validate_moqt()?;
2158                m.request_id.encode_moqt::<Wire>(buf);
2159                m.namespace_prefix.encode_moqt::<Wire>(buf);
2160                encode_parameters(&m.parameters, buf)?;
2161            }
2162            ControlMessage::TrackStatus(m) => {
2163                m.track_namespace.validate_moqt()?;
2164                check_track_name(&m.track_name)?;
2165                check_full_track_name(&m.track_namespace, &m.track_name)?;
2166                m.request_id.encode_moqt::<Wire>(buf);
2167                m.track_namespace.encode_moqt::<Wire>(buf);
2168                VarInt::from_usize(m.track_name.len()).encode_moqt::<Wire>(buf);
2169                buf.put_slice(&m.track_name);
2170                encode_parameters(&m.parameters, buf)?;
2171            }
2172            ControlMessage::Fetch(m) => {
2173                m.track_namespace.validate_moqt()?;
2174                check_track_name(&m.track_name)?;
2175                check_full_track_name(&m.track_namespace, &m.track_name)?;
2176                m.request_id.encode_moqt::<Wire>(buf);
2177                m.track_namespace.encode_moqt::<Wire>(buf);
2178                VarInt::from_usize(m.track_name.len()).encode_moqt::<Wire>(buf);
2179                buf.put_slice(&m.track_name);
2180                encode_parameters(&m.parameters, buf)?;
2181            }
2182            ControlMessage::PublishSkipped(m) => {
2183                m.namespace_suffix.validate_moqt()?;
2184                check_track_name(&m.track_name)?;
2185                check_full_track_name(&m.namespace_suffix, &m.track_name)?;
2186                m.namespace_suffix.encode_moqt::<Wire>(buf);
2187                VarInt::from_usize(m.track_name.len()).encode_moqt::<Wire>(buf);
2188                buf.put_slice(&m.track_name);
2189            }
2190        }
2191        Ok(())
2192    }
2193
2194    fn decode_body(msg_type: MessageType, buf: &mut impl Buf) -> Result<Self, CodecError> {
2195        match msg_type {
2196            MessageType::Setup => {
2197                let options = decode_setup_options(buf)?;
2198                Ok(ControlMessage::Setup(Setup { options }))
2199            }
2200            MessageType::GoAway => {
2201                let uri_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2202                // Draft-23 Section 9.2: "The maximum length of the New Session
2203                // URI is 8,192 bytes. If an endpoint receives a length
2204                // exceeding the maximum, it MUST close the session with
2205                // FIELD_LENGTH_EXCEEDED."
2206                if uri_len > MAX_GOAWAY_URI_LENGTH {
2207                    return Err(CodecError::GoAwayUriTooLong);
2208                }
2209                let uri = read_bytes(buf, uri_len)?;
2210                let timeout = VarInt::decode_moqt::<Wire>(buf)?;
2211                Ok(ControlMessage::GoAway(GoAway { new_session_uri: uri, timeout }))
2212            }
2213            MessageType::RequestOk => {
2214                let parameters = decode_parameters(buf)?;
2215                let track_properties = decode_track_properties(buf)?;
2216                Ok(ControlMessage::RequestOk(RequestOk { parameters, track_properties }))
2217            }
2218            MessageType::RequestError => {
2219                let error_code = VarInt::decode_moqt::<Wire>(buf)?;
2220                let retry_interval = VarInt::decode_moqt::<Wire>(buf)?;
2221                let reason_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2222                // Draft-23 Section 8.5: "If an endpoint receives a length
2223                // exceeding the maximum, it MUST close the session with
2224                // FIELD_LENGTH_EXCEEDED."
2225                if reason_len > MAX_REASON_PHRASE_LENGTH {
2226                    return Err(CodecError::ReasonPhraseTooLong);
2227                }
2228                let reason_phrase = read_bytes(buf, reason_len)?;
2229                // Section 9.4.1: "Error Details: Structured information about
2230                // the error, serialized as Key-Value-Pairs (Figure 4) spanning
2231                // the remainder of the message, bounded by the message Length
2232                // field."
2233                let error_details = decode_kvp_delta(buf)?;
2234                let m = RequestError { error_code, retry_interval, reason_phrase, error_details };
2235                check_error_details(&m)?;
2236                Ok(ControlMessage::RequestError(m))
2237            }
2238            MessageType::Subscribe => {
2239                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2240                let track_namespace = TrackNamespace::decode_moqt::<Wire>(buf)?;
2241                let tn_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2242                let track_name = read_bytes(buf, tn_len)?;
2243                check_full_track_name(&track_namespace, &track_name)?;
2244                let parameters = decode_parameters(buf)?;
2245                check_track_name(&track_name)?;
2246                Ok(ControlMessage::Subscribe(Subscribe {
2247                    request_id,
2248                    track_namespace,
2249                    track_name,
2250                    parameters,
2251                }))
2252            }
2253            MessageType::SubscribeOk => {
2254                let track_alias = VarInt::decode_moqt::<Wire>(buf)?;
2255                let parameters = decode_parameters(buf)?;
2256                let track_properties = decode_track_properties(buf)?;
2257                Ok(ControlMessage::SubscribeOk(SubscribeOk {
2258                    track_alias,
2259                    parameters,
2260                    track_properties,
2261                }))
2262            }
2263            MessageType::RequestUpdate => {
2264                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2265                let parameters = decode_parameters(buf)?;
2266                Ok(ControlMessage::RequestUpdate(RequestUpdate { request_id, parameters }))
2267            }
2268            MessageType::Publish => {
2269                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2270                let track_namespace = TrackNamespace::decode_moqt::<Wire>(buf)?;
2271                let tn_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2272                let track_name = read_bytes(buf, tn_len)?;
2273                let track_alias = VarInt::decode_moqt::<Wire>(buf)?;
2274                check_full_track_name(&track_namespace, &track_name)?;
2275                let parameters = decode_parameters(buf)?;
2276                let track_properties = decode_track_properties(buf)?;
2277                check_track_name(&track_name)?;
2278                Ok(ControlMessage::Publish(Publish {
2279                    request_id,
2280                    track_namespace,
2281                    track_name,
2282                    track_alias,
2283                    parameters,
2284                    track_properties,
2285                }))
2286            }
2287            MessageType::PublishStateNotify => {
2288                let parameters = decode_parameters(buf)?;
2289                Ok(ControlMessage::PublishStateNotify(PublishStateNotify { parameters }))
2290            }
2291            MessageType::PublishDone => {
2292                // Carried whatever it is; see [`PublishDone::status_code`].
2293                let status_code = VarInt::decode_moqt::<Wire>(buf)?;
2294                let stream_count = VarInt::decode_moqt::<Wire>(buf)?;
2295                let reason_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2296                // Draft-23 Section 8.5, as for REQUEST_ERROR above.
2297                if reason_len > MAX_REASON_PHRASE_LENGTH {
2298                    return Err(CodecError::ReasonPhraseTooLong);
2299                }
2300                let reason_phrase = read_bytes(buf, reason_len)?;
2301                Ok(ControlMessage::PublishDone(PublishDone {
2302                    status_code,
2303                    stream_count,
2304                    reason_phrase,
2305                }))
2306            }
2307            MessageType::PublishNamespace => {
2308                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2309                let track_namespace = TrackNamespace::decode_moqt::<Wire>(buf)?;
2310                let parameters = decode_parameters(buf)?;
2311                Ok(ControlMessage::PublishNamespace(PublishNamespace {
2312                    request_id,
2313                    track_namespace,
2314                    parameters,
2315                }))
2316            }
2317            MessageType::Namespace => {
2318                let namespace_suffix = TrackNamespace::decode_allow_empty_moqt::<Wire>(buf)?;
2319                let parameters = decode_parameters(buf)?;
2320                Ok(ControlMessage::Namespace(Namespace { namespace_suffix, parameters }))
2321            }
2322            MessageType::NamespaceDone => {
2323                let namespace_suffix = TrackNamespace::decode_allow_empty_moqt::<Wire>(buf)?;
2324                Ok(ControlMessage::NamespaceDone(NamespaceDone { namespace_suffix }))
2325            }
2326            MessageType::SubscribeNamespace => {
2327                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2328                let namespace_prefix = TrackNamespace::decode_allow_empty_moqt::<Wire>(buf)?;
2329                let parameters = decode_parameters(buf)?;
2330                Ok(ControlMessage::SubscribeNamespace(SubscribeNamespace {
2331                    request_id,
2332                    namespace_prefix,
2333                    parameters,
2334                }))
2335            }
2336            MessageType::SubscribeTracks => {
2337                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2338                let namespace_prefix = TrackNamespace::decode_allow_empty_moqt::<Wire>(buf)?;
2339                let parameters = decode_parameters(buf)?;
2340                Ok(ControlMessage::SubscribeTracks(SubscribeTracks {
2341                    request_id,
2342                    namespace_prefix,
2343                    parameters,
2344                }))
2345            }
2346            MessageType::TrackStatus => {
2347                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2348                let track_namespace = TrackNamespace::decode_moqt::<Wire>(buf)?;
2349                let tn_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2350                let track_name = read_bytes(buf, tn_len)?;
2351                check_full_track_name(&track_namespace, &track_name)?;
2352                let parameters = decode_parameters(buf)?;
2353                check_track_name(&track_name)?;
2354                Ok(ControlMessage::TrackStatus(TrackStatus {
2355                    request_id,
2356                    track_namespace,
2357                    track_name,
2358                    parameters,
2359                }))
2360            }
2361            MessageType::Fetch => {
2362                let request_id = VarInt::decode_moqt::<Wire>(buf)?;
2363                let track_namespace = TrackNamespace::decode_moqt::<Wire>(buf)?;
2364                let tn_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2365                let track_name = read_bytes(buf, tn_len)?;
2366                check_full_track_name(&track_namespace, &track_name)?;
2367                let parameters = decode_parameters(buf)?;
2368                check_track_name(&track_name)?;
2369                Ok(ControlMessage::Fetch(Fetch {
2370                    request_id,
2371                    track_namespace,
2372                    track_name,
2373                    parameters,
2374                }))
2375            }
2376            MessageType::PublishSkipped => {
2377                let namespace_suffix = TrackNamespace::decode_allow_empty_moqt::<Wire>(buf)?;
2378                let tn_len = VarInt::decode_moqt::<Wire>(buf)?.into_inner() as usize;
2379                let track_name = read_bytes(buf, tn_len)?;
2380                check_track_name(&track_name)?;
2381                check_full_track_name(&namespace_suffix, &track_name)?;
2382                Ok(ControlMessage::PublishSkipped(PublishSkipped { namespace_suffix, track_name }))
2383            }
2384        }
2385    }
2386
2387    pub fn message_type(&self) -> MessageType {
2388        match self {
2389            ControlMessage::Setup(_) => MessageType::Setup,
2390            ControlMessage::GoAway(_) => MessageType::GoAway,
2391            ControlMessage::RequestOk(_) => MessageType::RequestOk,
2392            ControlMessage::RequestError(_) => MessageType::RequestError,
2393            ControlMessage::Subscribe(_) => MessageType::Subscribe,
2394            ControlMessage::SubscribeOk(_) => MessageType::SubscribeOk,
2395            ControlMessage::RequestUpdate(_) => MessageType::RequestUpdate,
2396            ControlMessage::Publish(_) => MessageType::Publish,
2397            ControlMessage::PublishStateNotify(_) => MessageType::PublishStateNotify,
2398            ControlMessage::PublishDone(_) => MessageType::PublishDone,
2399            ControlMessage::PublishNamespace(_) => MessageType::PublishNamespace,
2400            ControlMessage::Namespace(_) => MessageType::Namespace,
2401            ControlMessage::NamespaceDone(_) => MessageType::NamespaceDone,
2402            ControlMessage::SubscribeNamespace(_) => MessageType::SubscribeNamespace,
2403            ControlMessage::SubscribeTracks(_) => MessageType::SubscribeTracks,
2404            ControlMessage::TrackStatus(_) => MessageType::TrackStatus,
2405            ControlMessage::Fetch(_) => MessageType::Fetch,
2406            ControlMessage::PublishSkipped(_) => MessageType::PublishSkipped,
2407        }
2408    }
2409}
2410
2411#[cfg(test)]
2412mod tests {
2413    use super::*;
2414
2415    /// Frame `body` as a draft-23 control message of `type_id`, declaring
2416    /// `declared_len` as its vi64 Message Length.
2417    fn frame_with_declared_len(type_id: u64, declared_len: u64, body: &[u8]) -> Vec<u8> {
2418        let mut out = Vec::new();
2419        VarInt::from_u64_moqt(type_id).encode_moqt::<Wire>(&mut out);
2420        VarInt::from_u64_moqt(declared_len).encode_moqt::<Wire>(&mut out);
2421        out.put_slice(body);
2422        out
2423    }
2424
2425    fn frame(type_id: u64, body: &[u8]) -> Vec<u8> {
2426        frame_with_declared_len(type_id, body.len() as u64, body)
2427    }
2428
2429    /// A SUBSCRIBE body: request id 1, namespace ("a"), track name "b", and
2430    /// `params` already encoded.
2431    fn subscribe_body(params: &[u8]) -> Vec<u8> {
2432        let mut body = vec![0x01, 0x01, 0x01, b'a', 0x01, b'b'];
2433        body.extend_from_slice(params);
2434        body
2435    }
2436
2437    fn param(key: u64, value: &[u8]) -> KeyValuePair {
2438        KeyValuePair { key: VarInt::from_u64_moqt(key), value: KvpValue::Bytes(value.to_vec()) }
2439    }
2440
2441    fn varint_pair(key: u64, value: u64) -> KeyValuePair {
2442        KeyValuePair {
2443            key: VarInt::from_u64_moqt(key),
2444            value: KvpValue::Varint(VarInt::from_u64_moqt(value)),
2445        }
2446    }
2447
2448    /// Section 9, Figure 6: "Message Length (vi64)". An empty REQUEST_OK is
2449    /// `07 01 00`.
2450    #[test]
2451    fn the_message_length_is_a_vi64() {
2452        let msg = ControlMessage::RequestOk(RequestOk {
2453            parameters: Vec::new(),
2454            track_properties: Vec::new(),
2455        });
2456        let mut out = Vec::new();
2457        msg.encode(&mut out).unwrap();
2458        assert_eq!(out, [0x07, 0x01, 0x00]);
2459
2460        // A non-minimal Length is valid (Section 8.1).
2461        let again = ControlMessage::decode(&mut &[0x07, 0xc0, 0x00, 0x01, 0x00][..]).unwrap();
2462        assert_eq!(again, msg);
2463
2464        // Two bytes of 16-bit Length read as a vi64 Length of 0 and a body
2465        // with no Number of Parameters.
2466        assert!(matches!(
2467            ControlMessage::decode(&mut &[0x07, 0x00, 0x01, 0x00][..]),
2468            Err(CodecError::ControlMessageLengthMismatch { declared: 0, .. })
2469        ));
2470    }
2471
2472    /// Section 9: "If an endpoint receives a control message with a length
2473    /// larger than its MAX_CONTROL_MESSAGE_SIZE, it MUST close the session with
2474    /// FIELD_LENGTH_EXCEEDED." The Length alone is enough to refuse it.
2475    #[test]
2476    fn a_length_past_the_limit_is_refused_before_the_body_arrives() {
2477        let mut head = Vec::new();
2478        VarInt::from_u64_moqt(0x05).encode_moqt::<Wire>(&mut head);
2479        VarInt::from_u64_moqt(70_000).encode_moqt::<Wire>(&mut head);
2480        assert_eq!(
2481            ControlMessage::decode(&mut &head[..]),
2482            Err(CodecError::ControlMessageExceedsLimit { length: 70_000, limit: 65535 })
2483        );
2484        assert_eq!(
2485            ControlMessage::decode_with_limit(&mut &head[..], 70_000),
2486            Err(CodecError::UnexpectedEnd)
2487        );
2488    }
2489
2490    /// Section 9: "An endpoint MUST NOT send a control message with a length
2491    /// larger than the peer's MAX_CONTROL_MESSAGE_SIZE (Section 9.1.8)."
2492    #[test]
2493    fn a_body_past_the_peers_limit_is_refused_on_encode() {
2494        let msg = ControlMessage::GoAway(GoAway {
2495            new_session_uri: vec![b'u'; 100],
2496            timeout: VarInt::from_u64_moqt(0),
2497        });
2498        let mut out = Vec::new();
2499        assert_eq!(
2500            msg.encode_with_limit(&mut out, 50),
2501            Err(CodecError::ControlMessageExceedsLimit { length: 102, limit: 50 })
2502        );
2503        assert!(out.is_empty());
2504        msg.encode_with_limit(&mut out, 102).unwrap();
2505    }
2506
2507    /// Table 5 lists 0x18 as RESERVED.
2508    #[test]
2509    fn fetch_ok_is_an_unknown_type() {
2510        assert_eq!(MessageType::from_id(0x18), None);
2511        let bytes = frame(0x18, &[0x00, 0x0a, 0x03, 0x00]);
2512        assert_eq!(
2513            ControlMessage::decode(&mut &bytes[..]),
2514            Err(CodecError::UnknownMessageType(0x18))
2515        );
2516    }
2517
2518    /// Draft-23 Section 9: "If the length does not match the length of the
2519    /// Message Body, the receiver MUST close the session with
2520    /// MALFORMED_MESSAGE."
2521    #[test]
2522    fn a_message_body_shorter_than_the_declared_length_is_refused() {
2523        let body = subscribe_body(&[0x00]);
2524        let mut junked = body.clone();
2525        junked.extend_from_slice(&[0xff, 0xff]);
2526        let bytes = frame_with_declared_len(0x03, (body.len() + 2) as u64, &junked);
2527
2528        assert_eq!(
2529            ControlMessage::decode(&mut &bytes[..]),
2530            Err(CodecError::ControlMessageLengthMismatch {
2531                declared: (body.len() + 2),
2532                detail: "its fields left bytes unread",
2533            })
2534        );
2535
2536        let honest = frame(0x03, &body);
2537        assert!(ControlMessage::decode(&mut &honest[..]).is_ok());
2538    }
2539
2540    /// Draft-23 Section 8.5: "The reason phrase length has a maximum value of
2541    /// 1024 bytes. If an endpoint receives a length exceeding the maximum, it
2542    /// MUST close the session with FIELD_LENGTH_EXCEEDED."
2543    #[test]
2544    fn an_over_long_reason_phrase_is_refused_on_decode() {
2545        for (type_id, prefix) in [(0x05u64, vec![0x01, 0x00]), (0x0B, vec![0x01, 0x00])] {
2546            let mut body = prefix;
2547            let over = MAX_REASON_PHRASE_LENGTH + 976;
2548            VarInt::from_usize(over).encode_moqt::<Wire>(&mut body);
2549            body.extend(std::iter::repeat_n(b'x', over));
2550            let bytes = frame(type_id, &body);
2551            assert_eq!(
2552                ControlMessage::decode(&mut &bytes[..]),
2553                Err(CodecError::ReasonPhraseTooLong),
2554                "message type 0x{type_id:x}"
2555            );
2556        }
2557    }
2558
2559    /// Draft-23 Section 9.2: "The maximum length of the New Session URI is
2560    /// 8,192 bytes. If an endpoint receives a length exceeding the maximum, it
2561    /// MUST close the session with FIELD_LENGTH_EXCEEDED."
2562    #[test]
2563    fn an_over_long_goaway_uri_is_refused_on_decode() {
2564        let over = MAX_GOAWAY_URI_LENGTH + 808;
2565        let mut body = Vec::new();
2566        VarInt::from_usize(over).encode_moqt::<Wire>(&mut body);
2567        body.extend(std::iter::repeat_n(b'u', over));
2568        body.push(0x00);
2569        let bytes = frame(0x10, &body);
2570        assert_eq!(ControlMessage::decode(&mut &bytes[..]), Err(CodecError::GoAwayUriTooLong));
2571    }
2572
2573    /// GROUP_ORDER allows 1 and 2 (Section 9.19.8) and PAUSED 0 and 1 (Section
2574    /// 9.19.18). 0x10 is not a draft-23 parameter.
2575    #[test]
2576    fn a_uint8_parameter_outside_its_range_is_refused() {
2577        let cases = [(0x22u8, 7u8, 2u8), (0x11, 2, 1)];
2578        for (key, bad, good) in cases {
2579            let bytes = frame(0x03, &subscribe_body(&[0x01, key, bad]));
2580            assert_eq!(
2581                ControlMessage::decode(&mut &bytes[..]),
2582                Err(CodecError::ParameterValueOutOfRange { key: key as u64, value: bad as u64 }),
2583                "parameter 0x{key:x} value {bad}"
2584            );
2585            let bytes = frame(0x03, &subscribe_body(&[0x01, key, good]));
2586            assert!(ControlMessage::decode(&mut &bytes[..]).is_ok(), "0x{key:x} = {good}");
2587        }
2588        let bytes = frame(0x03, &subscribe_body(&[0x01, 0x10, 0x01]));
2589        assert_eq!(
2590            ControlMessage::decode(&mut &bytes[..]),
2591            Err(CodecError::UnknownMessageParameter(0x10))
2592        );
2593    }
2594
2595    #[test]
2596    fn subscriber_priority_still_accepts_the_whole_byte_range() {
2597        for value in [0u8, 1, 2, 128, 255] {
2598            let bytes = frame(0x03, &subscribe_body(&[0x01, 0x20, value]));
2599            assert!(ControlMessage::decode(&mut &bytes[..]).is_ok(), "priority {value}");
2600        }
2601    }
2602
2603    /// Section 9.19.17: "The LARGEST_OBJECT parameter (Parameter Type 0x9) is
2604    /// a Location." Two bare varints, no length.
2605    #[test]
2606    fn largest_object_is_two_bare_varints() {
2607        let bytes = frame(0x07, &[0x01, 0x09, 0x0a, 0x03]);
2608        let msg = ControlMessage::decode(&mut &bytes[..]).expect("spec-correct frame must decode");
2609        let ControlMessage::RequestOk(ok) = &msg else {
2610            panic!("expected REQUEST_OK, got {msg:?}")
2611        };
2612        assert_eq!(ok.parameters, vec![param(0x09, &[0x0a, 0x03])]);
2613        let mut out = Vec::new();
2614        msg.encode(&mut out).expect("re-encode");
2615        assert_eq!(out, bytes);
2616    }
2617
2618    #[test]
2619    fn a_location_value_that_is_not_two_varints_is_refused_on_encode() {
2620        for value in [vec![0x0a], vec![0x0a, 0x03, 0x05]] {
2621            let msg = ControlMessage::RequestOk(RequestOk {
2622                parameters: vec![param(0x09, &value)],
2623                track_properties: Vec::new(),
2624            });
2625            assert!(msg.encode(&mut Vec::new()).is_err(), "{value:02x?}");
2626        }
2627    }
2628
2629    /// Section 9.19.20: TRACK_NAMESPACE_PREFIX "uses the Track Namespace
2630    /// encoding described in Section 8.7". No outer length.
2631    #[test]
2632    fn track_namespace_prefix_is_a_bare_track_namespace() {
2633        let namespace: Vec<u8> = [&[0x02, 0x04][..], b"live", &[0x06][..], b"sports"].concat();
2634        let body: Vec<u8> = [&[0x07, 0x01, 0x34][..], &namespace].concat();
2635        let bytes = frame(0x02, &body);
2636        let msg = ControlMessage::decode(&mut &bytes[..]).expect("spec-correct frame must decode");
2637        let ControlMessage::RequestUpdate(update) = &msg else { panic!("{msg:?}") };
2638        assert_eq!(update.parameters, vec![param(0x34, &namespace)]);
2639        let mut out = Vec::new();
2640        msg.encode(&mut out).unwrap();
2641        assert_eq!(out, bytes);
2642    }
2643
2644    /// Section 9.19.15: "Its value is a Number of Parameters (vi64) followed by
2645    /// that many Parameters". `23 02 0A 81 F4 17 01 01` is FILL_TIMEOUT 500 and
2646    /// a relative-start LOCATION_FILTER, and the outer chain resumes from 0x23.
2647    #[test]
2648    fn fill_parameters_is_a_count_and_no_length() {
2649        let params = [0x03, 0x21, 0x05, 0x02, 0x02, 0x0A, 0x81, 0xF4, 0x17, 0x01, 0x01, 0x0F, 0x40];
2650        let bytes = frame(0x03, &subscribe_body(&params));
2651        let msg = ControlMessage::decode(&mut &bytes[..]).expect("decodes");
2652        let ControlMessage::Subscribe(sub) = &msg else { panic!("{msg:?}") };
2653        assert_eq!(sub.parameters.len(), 3);
2654        assert_eq!(sub.parameters[1].key.into_inner(), FILL_PARAMETERS);
2655        assert_eq!(sub.parameters[2], varint_pair(0x32, 0x40));
2656        let KvpValue::Bytes(fill) = &sub.parameters[1].value else { panic!("{sub:?}") };
2657        let inner = decode_fill_parameters(fill).unwrap();
2658        assert_eq!(inner[0], varint_pair(0x0A, 500));
2659        assert_eq!(inner[1], param(0x21, &[0x01, 0x01]));
2660        let mut out = Vec::new();
2661        msg.encode(&mut out).unwrap();
2662        assert_eq!(out, bytes);
2663    }
2664
2665    /// FILL_PARAMETERS may appear in PUBLISH and SUBSCRIBE_TRACKS (Section
2666    /// 9.19.15), and not in FETCH.
2667    #[test]
2668    fn fill_parameters_scope() {
2669        assert!(parameter_in_scope(FILL_PARAMETERS, MessageType::Publish));
2670        assert!(parameter_in_scope(FILL_PARAMETERS, MessageType::SubscribeTracks));
2671        assert!(!parameter_in_scope(FILL_PARAMETERS, MessageType::Fetch));
2672    }
2673
2674    /// Section 2.4.1: "If an endpoint receives a Track Name with a length of 0,
2675    /// it MUST close the session with a PROTOCOL_VIOLATION."
2676    #[test]
2677    fn an_empty_track_name_is_refused() {
2678        let bytes = frame(0x03, &[0x02, 0x01, 0x01, b'a', 0x00, 0x00]);
2679        assert_eq!(ControlMessage::decode(&mut &bytes[..]), Err(CodecError::EmptyTrackName));
2680        let msg = ControlMessage::Subscribe(Subscribe {
2681            request_id: VarInt::from_u64_moqt(2),
2682            track_namespace: TrackNamespace(vec![b"a".to_vec()]),
2683            track_name: Vec::new(),
2684            parameters: Vec::new(),
2685        });
2686        assert_eq!(msg.encode(&mut Vec::new()), Err(CodecError::EmptyTrackName));
2687    }
2688
2689    /// Section 9.15, Figure 20: NAMESPACE ends with a parameter block, and no
2690    /// parameter definition names NAMESPACE.
2691    #[test]
2692    fn namespace_carries_a_parameter_block() {
2693        let bytes = frame(0x08, &[0x01, 0x01, b'a', 0x00]);
2694        let msg = ControlMessage::decode(&mut &bytes[..]).unwrap();
2695        assert_eq!(
2696            msg,
2697            ControlMessage::Namespace(Namespace {
2698                namespace_suffix: TrackNamespace(vec![b"a".to_vec()]),
2699                parameters: Vec::new(),
2700            })
2701        );
2702        let bytes = frame(0x08, &[0x01, 0x01, b'a', 0x01, 0x08, 0x05]);
2703        assert_eq!(
2704            ControlMessage::decode(&mut &bytes[..]),
2705            Err(CodecError::ParameterOutOfScope { key: 0x08, message_type: 0x08 })
2706        );
2707    }
2708
2709    /// Section 9.4.2.1: a REDIRECT Error Detail is Length-prefixed and MUST be
2710    /// present under Error Code REDIRECT.
2711    #[test]
2712    fn redirect_travels_in_an_error_detail() {
2713        let bytes = [0x05, 0x0B, 0x34, 0x00, 0x00, 0x01, 0x06, 0x00, 0x01, 0x01, b'a', 0x01, b'b'];
2714        let msg = ControlMessage::decode(&mut &bytes[..]).unwrap();
2715        let ControlMessage::RequestError(err) = &msg else { panic!("{msg:?}") };
2716        let redirect = err.redirect().unwrap().unwrap();
2717        assert_eq!(redirect.track_name, b"b");
2718        let mut out = Vec::new();
2719        msg.encode(&mut out).unwrap();
2720        assert_eq!(out, bytes);
2721
2722        assert_eq!(
2723            ControlMessage::decode(&mut &[0x05, 0x03, 0x34, 0x00, 0x00][..]),
2724            Err(CodecError::MissingErrorDetail { error_code: 0x34, detail_type: 0x01 })
2725        );
2726    }
2727
2728    /// Section 9.4.2.2: "Multiple instances of this type are allowed."
2729    #[test]
2730    fn unsupported_property_details_repeat() {
2731        let bytes = [0x05, 0x0B, 0x33, 0x00, 0x00, 0x02, 0xC0, 0x40, 0x00, 0x00, 0xC0, 0x40, 0x02];
2732        let msg = ControlMessage::decode(&mut &bytes[..]).unwrap();
2733        let ControlMessage::RequestError(err) = &msg else { panic!("{msg:?}") };
2734        assert_eq!(err.unsupported_properties(), vec![0x4000, 0x4002]);
2735    }
2736
2737    /// Section 9.3: Track Properties "are empty in PUBLISH_OK", and PUBLISH_OK
2738    /// carries EXPIRES alone.
2739    #[test]
2740    fn a_request_ok_is_held_to_the_request_it_answers() {
2741        let ok = RequestOk {
2742            parameters: vec![param(0x09, &[0x0a, 0x03])],
2743            track_properties: vec![varint_pair(0x30, 1)],
2744        };
2745        assert!(ok.check_answers(RequestOkKind::Fetch).is_ok());
2746        assert!(ok.check_answers(RequestOkKind::TrackStatus).is_ok());
2747        assert!(matches!(
2748            ok.check_answers(RequestOkKind::Publish),
2749            Err(CodecError::ParameterOutOfScope { key: 0x09, .. })
2750        ));
2751        let ok = RequestOk { parameters: Vec::new(), track_properties: vec![varint_pair(0x30, 1)] };
2752        assert_eq!(
2753            ok.check_answers(RequestOkKind::RequestUpdate),
2754            Err(CodecError::TrackPropertiesNotPermitted)
2755        );
2756    }
2757
2758    /// Section 9.1.8: odd Option Type 0x09 carrying one varint behind a
2759    /// Length, at least 65535.
2760    #[test]
2761    fn max_control_message_size_is_one_varint_behind_a_length() {
2762        let bytes = [0xAF, 0x00, 0x05, 0x09, 0x03, 0xC0, 0xFF, 0xFF];
2763        let msg = ControlMessage::decode(&mut &bytes[..]).unwrap();
2764        let ControlMessage::Setup(setup) = &msg else { panic!("{msg:?}") };
2765        assert_eq!(setup.max_control_message_size(), Ok(65535));
2766
2767        let short = Setup { options: vec![param(0x09, &encode_max_control_message_size(1000))] };
2768        assert_eq!(
2769            ControlMessage::Setup(short).encode(&mut Vec::new()),
2770            Err(CodecError::InvalidField)
2771        );
2772
2773        let two = [0xAF, 0x00, 0x04, 0x09, 0x02, 0x01, 0x02];
2774        assert!(matches!(
2775            ControlMessage::decode(&mut &two[..]),
2776            Err(CodecError::KeyValueFormatting { key: 0x09, .. })
2777        ));
2778    }
2779
2780    /// Section 10.4: "If an endpoint receives a value above 255, it MUST close
2781    /// the session with MALFORMED_KEY_VALUE."
2782    #[test]
2783    fn default_publisher_priority_above_255_is_refused() {
2784        let bytes = frame(0x07, &[0x00, 0x0E, 0x81, 0x00]);
2785        assert_eq!(
2786            ControlMessage::decode(&mut &bytes[..]),
2787            Err(CodecError::TrackPropertyValueOutOfRange { key: 0x0E, value: 256 })
2788        );
2789    }
2790
2791    /// Section 12.2: "When more than one code applies, an endpoint uses
2792    /// DELTA_ENCODING_OVERFLOW or FIELD_LENGTH_EXCEEDED in preference to the
2793    /// other codes." An empty Track Name (PROTOCOL_VIOLATION) followed by a
2794    /// Parameter Type delta that overflows is refused for the overflow, on
2795    /// each message that carries both.
2796    #[test]
2797    fn an_overflow_after_an_empty_track_name_is_the_one_reported() {
2798        // Namespace ("a"), empty Track Name.
2799        let name = [0x01, 0x01, 0x61, 0x00];
2800        // SUBSCRIBER_PRIORITY (0x20) of 0x80, then a delta of 2^64-1.
2801        let mut params = vec![0x02, 0x20, 0x80];
2802        VarInt::from_u64_moqt(u64::MAX).encode_moqt::<Wire>(&mut params);
2803        for (ty, alias) in [(0x03u64, false), (0x1D, true), (0x0D, false), (0x16, false)] {
2804            let mut body = vec![0x00];
2805            body.extend_from_slice(&name);
2806            if alias {
2807                body.push(0x07);
2808            }
2809            body.extend_from_slice(&params);
2810            let mut bytes = Vec::new();
2811            VarInt::from_u64_moqt(ty).encode_moqt::<Wire>(&mut bytes);
2812            VarInt::from_usize(body.len()).encode_moqt::<Wire>(&mut bytes);
2813            bytes.extend_from_slice(&body);
2814            assert!(
2815                matches!(
2816                    ControlMessage::decode(&mut &bytes[..]),
2817                    Err(CodecError::KeyDeltaOverflow(0x20, u64::MAX))
2818                ),
2819                "message type {ty:#x}"
2820            );
2821        }
2822    }
2823}