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 ¶meter.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(¶ms)?;
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 ¶meter.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(¶ms)?;
658 check_location_filters(¶ms)?;
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(¶ms));
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(¶ms);
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}