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