Skip to main content

moqtap_codec/draft12/
fields.rs

1use crate::draft12::message::*;
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 loc_to_json(loc: &Location) -> Value {
18    let mut o = Map::new();
19    o.insert("group".into(), vi(loc.group.into_inner()));
20    o.insert("object".into(), vi(loc.object.into_inner()));
21    Value::Map(o)
22}
23
24/// Parse an authorization_token byte value into JSON.
25///
26/// Draft-12 Section 8.2.1.1 Figure 4 gives the Token the same four fields
27/// draft-11 does, with the first deciding which of the others are on the wire:
28///
29/// ```text
30/// Token {
31///   Alias Type (i),
32///   [Token Alias (i),]
33///   [Token Type (i),]
34///   [Token Value (..)]
35/// }
36/// ```
37///
38/// So the second varint is the Token Alias on DELETE (0x0), REGISTER (0x1) and
39/// USE_ALIAS (0x2), and the Token Type only on USE_VALUE (0x3). See
40/// [`crate::auth_token::TokenAliasType`] for the table and draft-13's renderer
41/// for the branch this matches.
42///
43/// # What a value it cannot read renders as
44///
45/// The raw bytes, as `fields::params` and every other draft's renderer do.
46/// Field extraction runs on a message that has already decoded, so it has no
47/// refusal to give — and no guarantee the bytes are a Token. `setup_option_name`
48/// asks one draft to render a setup parameter that arrived under another, which
49/// is the whole point of that function and the one place nothing upstream has
50/// validated anything. `setup_option_name(12, &KeyValuePair { key: 0x03, value:
51/// KvpValue::Bytes(vec![]) })` is a public call with an empty value.
52fn auth_token_to_json(bytes: &[u8]) -> Value {
53    let mut buf = bytes;
54    let Ok(alias_type) = VarInt::decode(&mut buf) else {
55        return Value::Bytes(bytes.to_vec());
56    };
57    let at = alias_type.into_inner();
58    let mut o = Map::new();
59    o.insert("alias_type".into(), vi(at));
60    match at {
61        // DELETE, USE_ALIAS: an Alias and nothing else.
62        0 | 2 => {
63            if let Ok(ta) = VarInt::decode(&mut buf) {
64                o.insert("token_alias".into(), vi(ta.into_inner()));
65            }
66        }
67        // REGISTER: an Alias, a Type and a Value.
68        1 => {
69            if let Ok(ta) = VarInt::decode(&mut buf) {
70                o.insert("token_alias".into(), vi(ta.into_inner()));
71            }
72            if let Ok(tt) = VarInt::decode(&mut buf) {
73                o.insert("token_type".into(), vi(tt.into_inner()));
74            }
75            o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
76        }
77        // USE_VALUE (0x3), and any Alias Type this draft does not assign: a
78        // Type and a Value. An unassigned code has no serialization at all —
79        // Section 8.2.1.1 calls the Alias Type "an integer defining both the
80        // serialization and the processing behavior of the receiver" — so this
81        // arm is a guess, chosen to show the most of an unreadable value rather
82        // than because the draft says so.
83        _ => {
84            if let Ok(tt) = VarInt::decode(&mut buf) {
85                o.insert("token_type".into(), vi(tt.into_inner()));
86            }
87            o.insert("token_value".into(), Value::Bytes(buf.to_vec()));
88        }
89    }
90    Value::Map(o)
91}
92
93/// The four Setup Parameter Types Section 8.3.2 defines.
94///
95/// 0x03 is here and is not here on draft-11: Section 8.3.2.4 adds AUTHORIZATION
96/// TOKEN to the setup namespace by reference to Section 8.2.1.1, and this
97/// draft's `decode_setup_parameters` already admits and structurally validates
98/// it. The table has to name every parameter that decoder accepts, or a
99/// renderer answers `None` for one the same file reads.
100pub(crate) fn kvp_to_json_setup(params: &[KeyValuePair]) -> Value {
101    crate::fields::kvp_entries(params, |key, value| match (key, value) {
102        (0x01, KvpValue::Bytes(b)) => {
103            (Some("path"), Some(Value::Text(String::from_utf8_lossy(b).into_owned())))
104        }
105        (0x02, KvpValue::Varint(v)) => (Some("max_request_id"), Some(vi(v.into_inner()))),
106        (0x03, KvpValue::Bytes(b)) => (Some("authorization_token"), Some(auth_token_to_json(b))),
107        (0x04, KvpValue::Varint(v)) => {
108            (Some("max_auth_token_cache_size"), Some(vi(v.into_inner())))
109        }
110        _ => (None, None),
111    })
112}
113
114fn kvp_to_json_msg(params: &[KeyValuePair]) -> Value {
115    crate::fields::kvp_entries(params, |key, value| match (key, value) {
116        (0x03, KvpValue::Bytes(b)) => (Some("authorization_token"), Some(auth_token_to_json(b))),
117        (0x02, KvpValue::Varint(v)) => (Some("delivery_timeout"), Some(vi(v.into_inner()))),
118        (0x04, KvpValue::Varint(v)) => (Some("max_cache_duration"), Some(vi(v.into_inner()))),
119        _ => (None, None),
120    })
121}
122
123/// This draft's field names for a decoded control message.
124///
125/// Keys are the names this draft gives its fields, in the order it defines
126/// them. An optional field the message did not carry is absent rather than
127/// zero.
128pub fn message_fields(msg: &ControlMessage) -> Map {
129    let obj = match msg {
130        ControlMessage::ClientSetup(m) => {
131            let mut o = Map::new();
132            o.insert(
133                "supported_versions".into(),
134                Value::Array(m.supported_versions.iter().map(|v| vi(v.into_inner())).collect()),
135            );
136            o.insert("parameters".into(), kvp_to_json_setup(&m.parameters));
137            o
138        }
139        ControlMessage::ServerSetup(m) => {
140            let mut o = Map::new();
141            o.insert("selected_version".into(), vi(m.selected_version.into_inner()));
142            o.insert("parameters".into(), kvp_to_json_setup(&m.parameters));
143            o
144        }
145        ControlMessage::GoAway(m) => {
146            let mut o = Map::new();
147            o.insert(
148                "new_session_uri".into(),
149                Value::Text(String::from_utf8_lossy(&m.new_session_uri).into_owned()),
150            );
151            o
152        }
153        ControlMessage::MaxRequestId(m) => {
154            let mut o = Map::new();
155            o.insert("request_id".into(), vi(m.request_id.into_inner()));
156            o
157        }
158        ControlMessage::RequestsBlocked(m) => {
159            let mut o = Map::new();
160            o.insert("maximum_request_id".into(), vi(m.maximum_request_id.into_inner()));
161            o
162        }
163        ControlMessage::Subscribe(m) => {
164            let mut o = Map::new();
165            o.insert("request_id".into(), vi(m.request_id.into_inner()));
166            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
167            o.insert(
168                "track_name".into(),
169                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
170            );
171            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
172            o.insert("group_order".into(), vi(m.group_order as u64));
173            o.insert("forward".into(), vi(m.forward as u64));
174            o.insert("filter_type".into(), vi(m.filter_type.into_inner()));
175            if let Some(sg) = &m.start_group {
176                o.insert("start_group".into(), vi(sg.into_inner()));
177            }
178            if let Some(so) = &m.start_object {
179                o.insert("start_object".into(), vi(so.into_inner()));
180            }
181            if let Some(eg) = &m.end_group {
182                o.insert("end_group".into(), vi(eg.into_inner()));
183            }
184            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
185            o
186        }
187        ControlMessage::SubscribeOk(m) => {
188            let mut o = Map::new();
189            o.insert("request_id".into(), vi(m.request_id.into_inner()));
190            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
191            o.insert("expires".into(), vi(m.expires.into_inner()));
192            o.insert("group_order".into(), vi(m.group_order as u64));
193            o.insert("content_exists".into(), vi(m.content_exists as u64));
194            if let Some(loc) = &m.largest_location {
195                o.insert("largest_location".into(), loc_to_json(loc));
196            }
197            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
198            o
199        }
200        ControlMessage::SubscribeError(m) => {
201            let mut o = Map::new();
202            o.insert("request_id".into(), vi(m.request_id.into_inner()));
203            o.insert("error_code".into(), vi(m.error_code.into_inner()));
204            o.insert(
205                "reason_phrase".into(),
206                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
207            );
208            o
209        }
210        ControlMessage::SubscribeUpdate(m) => {
211            let mut o = Map::new();
212            o.insert("request_id".into(), vi(m.request_id.into_inner()));
213            o.insert("start_group".into(), vi(m.start_group.into_inner()));
214            o.insert("start_object".into(), vi(m.start_object.into_inner()));
215            o.insert("end_group".into(), vi(m.end_group.into_inner()));
216            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
217            o.insert("forward".into(), vi(m.forward as u64));
218            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
219            o
220        }
221        ControlMessage::SubscribeDone(m) => {
222            let mut o = Map::new();
223            o.insert("request_id".into(), vi(m.request_id.into_inner()));
224            o.insert("status_code".into(), vi(m.status_code.into_inner()));
225            o.insert("stream_count".into(), vi(m.stream_count.into_inner()));
226            o.insert(
227                "reason_phrase".into(),
228                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
229            );
230            o
231        }
232        ControlMessage::Unsubscribe(m) => {
233            let mut o = Map::new();
234            o.insert("request_id".into(), vi(m.request_id.into_inner()));
235            o
236        }
237        ControlMessage::Announce(m) => {
238            let mut o = Map::new();
239            o.insert("request_id".into(), vi(m.request_id.into_inner()));
240            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
241            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
242            o
243        }
244        ControlMessage::AnnounceOk(m) => {
245            let mut o = Map::new();
246            o.insert("request_id".into(), vi(m.request_id.into_inner()));
247            o
248        }
249        ControlMessage::AnnounceError(m) => {
250            let mut o = Map::new();
251            o.insert("request_id".into(), vi(m.request_id.into_inner()));
252            o.insert("error_code".into(), vi(m.error_code.into_inner()));
253            o.insert(
254                "reason_phrase".into(),
255                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
256            );
257            o
258        }
259        ControlMessage::AnnounceCancel(m) => {
260            let mut o = Map::new();
261            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
262            o.insert("error_code".into(), vi(m.error_code.into_inner()));
263            o.insert(
264                "reason_phrase".into(),
265                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
266            );
267            o
268        }
269        ControlMessage::Unannounce(m) => {
270            let mut o = Map::new();
271            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
272            o
273        }
274        ControlMessage::SubscribeAnnounces(m) => {
275            let mut o = Map::new();
276            o.insert("request_id".into(), vi(m.request_id.into_inner()));
277            o.insert("track_namespace_prefix".into(), ns_to_json(&m.track_namespace_prefix));
278            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
279            o
280        }
281        ControlMessage::SubscribeAnnouncesOk(m) => {
282            let mut o = Map::new();
283            o.insert("request_id".into(), vi(m.request_id.into_inner()));
284            o
285        }
286        ControlMessage::SubscribeAnnouncesError(m) => {
287            let mut o = Map::new();
288            o.insert("request_id".into(), vi(m.request_id.into_inner()));
289            o.insert("error_code".into(), vi(m.error_code.into_inner()));
290            o.insert(
291                "reason_phrase".into(),
292                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
293            );
294            o
295        }
296        ControlMessage::UnsubscribeAnnounces(m) => {
297            let mut o = Map::new();
298            o.insert("track_namespace_prefix".into(), ns_to_json(&m.track_namespace_prefix));
299            o
300        }
301        ControlMessage::TrackStatusRequest(m) => {
302            let mut o = Map::new();
303            o.insert("request_id".into(), vi(m.request_id.into_inner()));
304            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
305            o.insert(
306                "track_name".into(),
307                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
308            );
309            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
310            o
311        }
312        ControlMessage::TrackStatus(m) => {
313            let mut o = Map::new();
314            o.insert("request_id".into(), vi(m.request_id.into_inner()));
315            o.insert("status_code".into(), vi(m.status_code.into_inner()));
316            o.insert("largest_location".into(), loc_to_json(&m.largest_location));
317            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
318            o
319        }
320        ControlMessage::Fetch(m) => {
321            let mut o = Map::new();
322            o.insert("request_id".into(), vi(m.request_id.into_inner()));
323            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
324            o.insert("group_order".into(), vi(m.group_order as u64));
325            o.insert("fetch_type".into(), vi(m.fetch_type as u64));
326            match &m.fetch_payload {
327                FetchPayload::Standalone {
328                    track_namespace,
329                    track_name,
330                    start_group,
331                    start_object,
332                    end_group,
333                    end_object,
334                } => {
335                    o.insert("track_namespace".into(), ns_to_json(track_namespace));
336                    o.insert(
337                        "track_name".into(),
338                        Value::Text(String::from_utf8_lossy(track_name).into_owned()),
339                    );
340                    o.insert("start_group".into(), vi(start_group.into_inner()));
341                    o.insert("start_object".into(), vi(start_object.into_inner()));
342                    o.insert("end_group".into(), vi(end_group.into_inner()));
343                    o.insert("end_object".into(), vi(end_object.into_inner()));
344                }
345                FetchPayload::Joining { joining_request_id, joining_start } => {
346                    // The key is the corpus's spelling, not this draft's. The
347                    // draft renamed the field to Joining Request ID; the shared
348                    // vector files still say joining_subscribe_id, and they are
349                    // maintained elsewhere, so the name is translated here
350                    // rather than changed there.
351                    o.insert("joining_subscribe_id".into(), vi(joining_request_id.into_inner()));
352                    o.insert("joining_start".into(), vi(joining_start.into_inner()));
353                }
354            }
355            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
356            o
357        }
358        ControlMessage::FetchOk(m) => {
359            let mut o = Map::new();
360            o.insert("request_id".into(), vi(m.request_id.into_inner()));
361            o.insert("group_order".into(), vi(m.group_order as u64));
362            o.insert("end_of_track".into(), vi(m.end_of_track as u64));
363            o.insert("end_location".into(), loc_to_json(&m.end_location));
364            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
365            o
366        }
367        ControlMessage::FetchError(m) => {
368            let mut o = Map::new();
369            o.insert("request_id".into(), vi(m.request_id.into_inner()));
370            o.insert("error_code".into(), vi(m.error_code.into_inner()));
371            o.insert(
372                "reason_phrase".into(),
373                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
374            );
375            o
376        }
377        ControlMessage::FetchCancel(m) => {
378            let mut o = Map::new();
379            o.insert("request_id".into(), vi(m.request_id.into_inner()));
380            o
381        }
382        ControlMessage::Publish(m) => {
383            let mut o = Map::new();
384            o.insert("request_id".into(), vi(m.request_id.into_inner()));
385            o.insert("track_namespace".into(), ns_to_json(&m.track_namespace));
386            o.insert(
387                "track_name".into(),
388                Value::Text(String::from_utf8_lossy(&m.track_name).into_owned()),
389            );
390            o.insert("track_alias".into(), vi(m.track_alias.into_inner()));
391            o.insert("group_order".into(), vi(m.group_order as u64));
392            o.insert("content_exists".into(), vi(m.content_exists as u64));
393            if let Some(loc) = &m.largest_location {
394                o.insert("largest_location".into(), loc_to_json(loc));
395            }
396            o.insert("forward".into(), vi(m.forward as u64));
397            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
398            o
399        }
400        ControlMessage::PublishOk(m) => {
401            let mut o = Map::new();
402            o.insert("request_id".into(), vi(m.request_id.into_inner()));
403            o.insert("forward".into(), vi(m.forward as u64));
404            o.insert("subscriber_priority".into(), vi(m.subscriber_priority as u64));
405            o.insert("group_order".into(), vi(m.group_order as u64));
406            o.insert("filter_type".into(), vi(m.filter_type.into_inner()));
407            if let Some(sg) = &m.start_group {
408                o.insert("start_group".into(), vi(sg.into_inner()));
409            }
410            if let Some(so) = &m.start_object {
411                o.insert("start_object".into(), vi(so.into_inner()));
412            }
413            if let Some(eg) = &m.end_group {
414                o.insert("end_group".into(), vi(eg.into_inner()));
415            }
416            o.insert("parameters".into(), kvp_to_json_msg(&m.parameters));
417            o
418        }
419        ControlMessage::PublishError(m) => {
420            let mut o = Map::new();
421            o.insert("request_id".into(), vi(m.request_id.into_inner()));
422            o.insert("error_code".into(), vi(m.error_code.into_inner()));
423            o.insert(
424                "reason_phrase".into(),
425                Value::Text(String::from_utf8_lossy(&m.reason_phrase).into_owned()),
426            );
427            o
428        }
429    };
430    obj
431}