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