Skip to main content

moqtap_codec/draft15/
fields.rs

1use crate::draft15::message::ControlMessage;
2use crate::fields::{FieldMap as Map, FieldValue as Value};
3use crate::kvp::{KeyValuePair, KvpValue};
4use crate::types::*;
5use crate::varint::VarInt;
6
7fn vi(v: u64) -> Value {
8    Value::Uint(v)
9}
10
11fn ns_to_json(ns: &TrackNamespace) -> Value {
12    Value::Array(
13        ns.0.iter().map(|e| Value::Text(String::from_utf8_lossy(e).into_owned())).collect(),
14    )
15}
16
17fn d15_setup_param_name(key: u64) -> Option<&'static str> {
18    match key {
19        0x01 => Some("path"),
20        0x02 => Some("max_request_id"),
21        0x03 => Some("authorization_token"),
22        0x04 => Some("max_auth_token_cache_size"),
23        0x05 => Some("authority"),
24        0x07 => Some("moqt_implementation"),
25        _ => None,
26    }
27}
28
29fn d15_msg_param_name(key: u64) -> Option<&'static str> {
30    match key {
31        0x02 => Some("delivery_timeout"),
32        0x03 => Some("authorization_token"),
33        0x04 => Some("max_cache_duration"),
34        0x08 => Some("expires"),
35        0x09 => Some("largest_object"),
36        0x0e => Some("publisher_priority"),
37        0x10 => Some("forward"),
38        0x20 => Some("subscriber_priority"),
39        0x21 => Some("subscription_filter"),
40        0x22 => Some("group_order"),
41        0x30 => Some("dynamic_groups"),
42        0x32 => Some("new_group_request"),
43        _ => None,
44    }
45}
46
47fn decode_subscription_filter(bytes: &[u8]) -> Value {
48    let mut buf = bytes;
49    let filter_type = VarInt::decode(&mut buf).unwrap().into_inner();
50    let mut obj = Map::new();
51    obj.insert("filter_type".into(), vi(filter_type));
52    match filter_type {
53        3 => {
54            // AbsoluteStart
55            let start_group = VarInt::decode(&mut buf).unwrap().into_inner();
56            let start_object = VarInt::decode(&mut buf).unwrap().into_inner();
57            obj.insert("start_group".into(), vi(start_group));
58            obj.insert("start_object".into(), vi(start_object));
59        }
60        4 => {
61            // AbsoluteRange
62            let start_group = VarInt::decode(&mut buf).unwrap().into_inner();
63            let start_object = VarInt::decode(&mut buf).unwrap().into_inner();
64            let end_group = VarInt::decode(&mut buf).unwrap().into_inner();
65            obj.insert("start_group".into(), vi(start_group));
66            obj.insert("start_object".into(), vi(start_object));
67            obj.insert("end_group".into(), vi(end_group));
68        }
69        _ => {
70            // LatestGroup (1), LatestObject (2), or unknown — no extra fields
71        }
72    }
73    Value::Map(obj)
74}
75
76/// Render a draft-15 LARGEST_OBJECT (0x09) parameter value: a Group and an
77/// Object, as two varints.
78///
79/// # Nothing has checked that the value is two varints
80///
81/// Drafts 17 and later give 0x09 a `Location` encoding: their decoders read the
82/// two varints and re-serialise them into the stored value, so what reaches
83/// their extractor is two varints by construction. Draft-15 has no such table.
84/// 0x09 is an odd Type, so `KeyValuePair::decode` keeps whatever
85/// length-prefixed bytes arrived, and none of `decode_parameters`' four checks
86/// — duplicates, authorization tokens, varint value ranges, subscription
87/// filters — looks at 0x09. `KNOWN_VERSION_SPECIFIC_PARAMETERS` admits it and
88/// `check_parameter_scope` permits it on SUBSCRIBE_OK, so an eight-byte
89/// SUBSCRIBE_OK carrying `0x09` with an empty value reaches here.
90///
91/// An empty value fails the first read and a single `0x00` fails the *second*,
92/// which is the nastier of the two: the first varint decodes cleanly and the
93/// value looks well formed right up to the point where it is not.
94///
95/// # What a value it cannot read renders as
96///
97/// The raw bytes, as `fields::params` and this file's own
98/// `auth_token_to_json_d15` do. Field extraction runs on a message that has
99/// already decoded, so it has no refusal to give: what a peer sent is what
100/// there is to show.
101fn decode_largest_object(bytes: &[u8]) -> Value {
102    let mut buf = bytes;
103    let Ok(group) = VarInt::decode(&mut buf) else {
104        return Value::Bytes(bytes.to_vec());
105    };
106    let Ok(object) = VarInt::decode(&mut buf) else {
107        return Value::Bytes(bytes.to_vec());
108    };
109    let mut obj = Map::new();
110    obj.insert("group".into(), vi(group.into_inner()));
111    obj.insert("object".into(), vi(object.into_inner()));
112    Value::Map(obj)
113}
114
115/// Parse an authorization_token byte value into structured JSON.
116fn auth_token_to_json_d15(bytes: &[u8]) -> Value {
117    let mut buf = bytes;
118    let alias_type = match VarInt::decode(&mut buf) {
119        Ok(v) => v,
120        Err(_) => return Value::Bytes(bytes.to_vec()),
121    };
122    let at = alias_type.into_inner();
123    let mut o = Map::new();
124    o.insert("alias_type".into(), vi(at));
125    match at {
126        0 | 2 => {
127            if let Ok(ta) = VarInt::decode(&mut buf) {
128                o.insert("token_alias".into(), vi(ta.into_inner()));
129            }
130        }
131        1 => {
132            if let Ok(ta) = VarInt::decode(&mut buf) {
133                o.insert("token_alias".into(), vi(ta.into_inner()));
134            }
135            if let Ok(tt) = VarInt::decode(&mut buf) {
136                o.insert("token_type".into(), vi(tt.into_inner()));
137            }
138            o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
139        }
140        _ => {
141            if let Ok(tt) = VarInt::decode(&mut buf) {
142                o.insert("token_type".into(), vi(tt.into_inner()));
143            }
144            o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
145        }
146    }
147    Value::Map(o)
148}
149
150fn kvp_to_json_d15_inner(
151    params: &[KeyValuePair],
152    name_fn: fn(u64) -> Option<&'static str>,
153) -> Value {
154    let mut obj = Map::new();
155    let mut unknown = Vec::new();
156
157    for p in params {
158        let key = p.key.into_inner();
159        if let Some(name) = name_fn(key) {
160            match (&p.value, key) {
161                (KvpValue::Bytes(b), 0x21) => {
162                    obj.insert(name.to_string(), decode_subscription_filter(b));
163                }
164                (KvpValue::Bytes(b), 0x09) => {
165                    obj.insert(name.to_string(), decode_largest_object(b));
166                }
167                (KvpValue::Bytes(b), _) if name == "authorization_token" => {
168                    obj.insert(name.to_string(), auth_token_to_json_d15(b));
169                }
170                (KvpValue::Varint(v), _) => {
171                    obj.insert(name.to_string(), vi(v.into_inner()));
172                }
173                (KvpValue::Bytes(b), _) => {
174                    obj.insert(
175                        name.to_string(),
176                        Value::Text(String::from_utf8_lossy(b).into_owned()),
177                    );
178                }
179            }
180        } else {
181            let mut entry = Map::new();
182            entry.insert("id".to_string(), Value::Text(format!("0x{:x}", key)));
183            match &p.value {
184                KvpValue::Varint(v) => {
185                    entry.insert("length".to_string(), vi(v.into_inner()));
186                }
187                KvpValue::Bytes(b) => {
188                    entry.insert("length".to_string(), vi(b.len() as u64));
189                    entry.insert("raw_hex".to_string(), Value::Bytes(b.to_vec()));
190                }
191            }
192            unknown.push(Value::Map(entry));
193        }
194    }
195
196    if !unknown.is_empty() {
197        obj.insert("unknown".to_string(), Value::Array(unknown));
198    }
199
200    Value::Map(obj)
201}
202
203fn kvp_to_json_d15(params: &[KeyValuePair]) -> Value {
204    kvp_to_json_d15_inner(params, d15_msg_param_name)
205}
206
207fn kvp_to_json_d15_setup(params: &[KeyValuePair]) -> Value {
208    kvp_to_json_d15_inner(params, d15_setup_param_name)
209}
210
211/// This draft's field names for a decoded control message.
212///
213/// Keys are the names this draft gives its fields, in the order it defines
214/// them. An optional field the message did not carry is absent rather than
215/// zero.
216pub fn message_fields(msg: &ControlMessage) -> Map {
217    let obj = match msg {
218        ControlMessage::ClientSetup(m) => {
219            let mut o = Map::new();
220            o.insert("parameters".into(), kvp_to_json_d15_setup(&m.parameters));
221            o
222        }
223        ControlMessage::ServerSetup(m) => {
224            let mut o = Map::new();
225            o.insert("parameters".into(), kvp_to_json_d15_setup(&m.parameters));
226            o
227        }
228        ControlMessage::GoAway(m) => {
229            let mut o = Map::new();
230            o.insert(
231                "new_session_uri".into(),
232                Value::Text(String::from_utf8_lossy(&m.new_session_uri).into_owned()),
233            );
234            o
235        }
236        ControlMessage::MaxRequestId(m) => {
237            let mut o = Map::new();
238            o.insert("max_request_id".into(), vi(m.request_id.into_inner()));
239            o
240        }
241        ControlMessage::RequestsBlocked(m) => {
242            let mut o = Map::new();
243            o.insert("maximum_request_id".into(), vi(m.maximum_request_id.into_inner()));
244            o
245        }
246        ControlMessage::RequestOk(m) => {
247            let mut o = Map::new();
248            o.insert("request_id".into(), vi(m.request_id.into_inner()));
249            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
250            o
251        }
252        ControlMessage::RequestError(m) => {
253            let mut o = Map::new();
254            o.insert("request_id".into(), vi(m.request_id.into_inner()));
255            o.insert("error_code".into(), vi(m.error_code.into_inner()));
256            o.insert(
257                "reason_phrase".into(),
258                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
259            );
260            o
261        }
262        ControlMessage::Subscribe(m) => {
263            let mut o = Map::new();
264            o.insert("request_id".into(), vi(m.request_id.into_inner()));
265            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
266            o.insert(
267                "track_name".into(),
268                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
269            );
270            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
271            o
272        }
273        ControlMessage::SubscribeOk(m) => {
274            let mut o = Map::new();
275            o.insert("request_id".into(), vi(m.request_id.into_inner()));
276            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
277            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
278            o
279        }
280        ControlMessage::SubscribeUpdate(m) => {
281            let mut o = Map::new();
282            o.insert("request_id".into(), vi(m.request_id.into_inner()));
283            o.insert("subscription_request_id".into(), vi(m.subscription_request_id.into_inner()));
284            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
285            o
286        }
287        ControlMessage::Unsubscribe(m) => {
288            let mut o = Map::new();
289            o.insert("request_id".into(), vi(m.request_id.into_inner()));
290            o
291        }
292        ControlMessage::Publish(m) => {
293            let mut o = Map::new();
294            o.insert("request_id".into(), vi(m.request_id.into_inner()));
295            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
296            o.insert(
297                "track_name".into(),
298                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
299            );
300            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
301            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
302            o
303        }
304        ControlMessage::PublishOk(m) => {
305            let mut o = Map::new();
306            o.insert("request_id".into(), vi(m.request_id.into_inner()));
307            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
308            o
309        }
310        ControlMessage::PublishDone(m) => {
311            let mut o = Map::new();
312            o.insert("request_id".into(), vi(m.request_id.into_inner()));
313            o.insert("status_code".into(), vi(m.status_code.into_inner()));
314            o.insert("stream_count".into(), vi(m.stream_count.into_inner()));
315            o.insert(
316                "reason_phrase".into(),
317                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
318            );
319            o
320        }
321        ControlMessage::PublishNamespace(m) => {
322            let mut o = Map::new();
323            o.insert("request_id".into(), vi(m.request_id.into_inner()));
324            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
325            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
326            o
327        }
328        ControlMessage::PublishNamespaceDone(m) => {
329            let mut o = Map::new();
330            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
331            o
332        }
333        ControlMessage::PublishNamespaceCancel(m) => {
334            let mut o = Map::new();
335            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
336            o.insert("error_code".into(), vi(m.error_code.into_inner()));
337            o.insert(
338                "reason_phrase".into(),
339                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
340            );
341            o
342        }
343        ControlMessage::SubscribeNamespace(m) => {
344            let mut o = Map::new();
345            o.insert("request_id".into(), vi(m.request_id.into_inner()));
346            o.insert("namespace_prefix".into(), ns_to_json(&m.namespace_prefix));
347            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
348            o
349        }
350        ControlMessage::UnsubscribeNamespace(m) => {
351            let mut o = Map::new();
352            o.insert("request_id".into(), vi(m.request_id.into_inner()));
353            o
354        }
355        ControlMessage::TrackStatus(m) => {
356            let mut o = Map::new();
357            o.insert("request_id".into(), vi(m.request_id.into_inner()));
358            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
359            o.insert(
360                "track_name".into(),
361                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
362            );
363            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
364            o
365        }
366        ControlMessage::Fetch(m) => {
367            let mut o = Map::new();
368            o.insert("request_id".into(), vi(m.request_id.into_inner()));
369            o.insert("fetch_type".into(), vi(m.fetch_type as u64));
370            match &m.fetch_payload {
371                crate::draft15::message::FetchPayload::Standalone {
372                    track_namespace,
373                    track_name,
374                    start_group,
375                    start_object,
376                    end_group,
377                    end_object,
378                } => {
379                    o.insert("track_namespace".into(), ns_to_json(track_namespace));
380                    o.insert(
381                        "track_name".into(),
382                        Value::Text(String::from_utf8_lossy(track_name).into_owned()),
383                    );
384                    o.insert("start_group".into(), vi(start_group.into_inner()));
385                    o.insert("start_object".into(), vi(start_object.into_inner()));
386                    o.insert("end_group".into(), vi(end_group.into_inner()));
387                    o.insert("end_object".into(), vi(end_object.into_inner()));
388                }
389                crate::draft15::message::FetchPayload::Joining {
390                    joining_request_id,
391                    joining_start,
392                } => {
393                    o.insert("joining_request_id".into(), vi(joining_request_id.into_inner()));
394                    o.insert("joining_start".into(), vi(joining_start.into_inner()));
395                }
396            }
397            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
398            o
399        }
400        ControlMessage::FetchOk(m) => {
401            let mut o = Map::new();
402            o.insert("request_id".into(), vi(m.request_id.into_inner()));
403            o.insert("end_of_track".into(), vi(m.end_of_track as u64));
404            o.insert("end_group".into(), vi(m.end_group.into_inner()));
405            o.insert("end_object".into(), vi(m.end_object.into_inner()));
406            o.insert("parameters".into(), kvp_to_json_d15(&m.parameters));
407            o
408        }
409        ControlMessage::FetchCancel(m) => {
410            let mut o = Map::new();
411            o.insert("request_id".into(), vi(m.request_id.into_inner()));
412            o
413        }
414    };
415    obj
416}