Skip to main content

moqtap_codec/fields/
params.rs

1use crate::fields::FieldValue as Value;
2use crate::kvp::{KeyValuePair, KvpValue};
3use crate::varint::VarInt;
4
5/// Known parameter names for draft-07 SETUP messages.
6#[cfg(feature = "draft07")]
7fn d07_setup_param_name(key: u64) -> Option<&'static str> {
8    match key {
9        0x00 => Some("role"),
10        0x01 => Some("path"),
11        0x02 => Some("max_subscribe_id"),
12        _ => None,
13    }
14}
15
16/// Known parameter names for draft-07 non-SETUP messages.
17fn d07_message_param_name(key: u64) -> Option<&'static str> {
18    match key {
19        0x02 => Some("authorization_info"),
20        0x03 => Some("delivery_timeout"),
21        0x04 => Some("max_cache_duration"),
22        _ => None,
23    }
24}
25
26/// Draft-07 setup varint parameter keys.
27#[cfg(feature = "draft07")]
28fn d07_setup_is_varint(key: u64) -> bool {
29    matches!(key, 0x00 | 0x02) // role, max_subscribe_id
30}
31
32/// Known parameter names for SETUP messages in drafts 08 through 10.
33///
34/// The same two as draft-07 minus ROLE, which those drafts do not define: the
35/// word occurs nowhere in the text of any of them, and 0x00 is not given to
36/// anything else. Naming it here anyway would report a parameter the sender
37/// cannot have meant, and it read the value as an integer that no decoder had
38/// checked was one.
39#[cfg(any(feature = "draft08", feature = "draft09", feature = "draft10"))]
40fn d08_setup_param_name(key: u64) -> Option<&'static str> {
41    match key {
42        0x01 => Some("path"),
43        0x02 => Some("max_subscribe_id"),
44        _ => None,
45    }
46}
47
48/// Setup varint parameter keys for drafts 08 through 10.
49#[cfg(any(feature = "draft08", feature = "draft09", feature = "draft10"))]
50fn d08_setup_is_varint(key: u64) -> bool {
51    key == 0x02 // max_subscribe_id
52}
53
54/// Draft-07 message varint parameter keys.
55fn d07_msg_is_varint(key: u64) -> bool {
56    matches!(key, 0x03 | 0x04) // delivery_timeout, max_cache_duration
57}
58
59/// Convert draft-07 KVP list to JSON. In draft-07, all values are length-prefixed
60/// bytes. For known varint parameters, decode the bytes as a VarInt.
61fn kvp_to_json_d07_inner(
62    params: &[KeyValuePair],
63    name_fn: fn(u64) -> Option<&'static str>,
64    is_varint_fn: fn(u64) -> bool,
65) -> Value {
66    crate::fields::kvp_entries(params, |key, value| {
67        let Some(name) = name_fn(key) else {
68            return (None, None);
69        };
70        let rendered = match value {
71            KvpValue::Bytes(b) if is_varint_fn(key) => {
72                // The bytes come off the wire and the decoder does not
73                // always vouch for them: it refuses a value that is not one
74                // varint only for the types the draft in question defines
75                // as an integer, and this table is shared by four drafts
76                // that do not define the same set. A type one of them
77                // dropped arrives unchecked, so a value too short to be a
78                // varint reaches here.
79                //
80                // `None` rather than a refusal: this is what a message
81                // carried, not a judgement on whether it was allowed to, and
82                // an entry with no `value` reports the bytes under `raw_hex`.
83                match VarInt::decode(&mut &b[..]) {
84                    Ok(v) => Some(Value::Uint(v.into_inner())),
85                    Err(_) => None,
86                }
87            }
88            KvpValue::Bytes(b) => Some(Value::Text(String::from_utf8_lossy(b).into_owned())),
89            KvpValue::Varint(v) => Some(Value::Uint(v.into_inner())),
90        };
91        (Some(name), rendered)
92    })
93}
94
95#[cfg(feature = "draft07")]
96pub fn kvp_to_json_d07_setup(params: &[KeyValuePair]) -> Value {
97    kvp_to_json_d07_inner(params, d07_setup_param_name, d07_setup_is_varint)
98}
99
100pub fn kvp_to_json_d07(params: &[KeyValuePair]) -> Value {
101    kvp_to_json_d07_inner(params, d07_message_param_name, d07_msg_is_varint)
102}
103
104/// The setup parameter list of a draft that dropped ROLE.
105#[cfg(any(feature = "draft08", feature = "draft09", feature = "draft10"))]
106pub fn kvp_to_json_d08_setup(params: &[KeyValuePair]) -> Value {
107    kvp_to_json_d07_inner(params, d08_setup_param_name, d08_setup_is_varint)
108}