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