Skip to main content

macula_rust/frame/
envelope.rs

1//! Wire 1.0's frame envelope (WIRE_1_0.md section 3, macula#99): every frame,
2//! of every type, carries version 5 and a frame_type of 1 to 64 bytes, and its
3//! other envelope keys only where it has a value for them. Additions arrive in
4//! `ext`, never as new core fields; an unknown frame type is read past.
5
6use crate::cbor::Value;
7
8use super::wire_counters::{count_ext_ignored, count_ext_refused, count_unknown_frame_type};
9use super::{protocol_uint, FrameError, PROTOCOL_VERSION};
10
11/// The bounds of a frame_type, an extension name and an `ext` map.
12pub const MAX_FRAME_TYPE_BYTES: usize = 64;
13pub const MAX_EXTENSION_NAME_BYTES: usize = 64;
14pub const MAX_EXTENSIONS: usize = 16;
15
16/// The QUIC application code a dedicated stream is aborted with when its
17/// frame is of a type the receiver does not know (WIRE_1_0.md section 3.3),
18/// distinct from 3, "did not decode".
19pub const QUIC_CODE_UNKNOWN_FRAME_TYPE: u32 = 5;
20
21/// The extensions this crate acts on. Wire 1.0 defines none; each arrives
22/// with the capability bit that announces it.
23const KNOWN_EXTENSIONS: &[&str] = &[];
24
25/// A received frame as wire 1.0 reads it: its type, and the frame without
26/// `ext`, so the type's own table never sees it.
27#[derive(Debug, Clone, PartialEq)]
28pub struct Envelope {
29    pub frame_type: String,
30    pub frame: Value,
31}
32
33/// Reads a received frame's envelope: a map with text keys, version 5, a
34/// frame_type of 1 to 64 bytes, each shared envelope key of its type, and an
35/// `ext` map of 1 to 16 well-formed extensions, acted on. The dropped
36/// `capabilities` header is malformed. An unknown critical extension is
37/// [`FrameError::ExtensionUnsupported`]; an unknown non-critical one is
38/// counted and read past. An optional key is absent or of its type, never
39/// null. Keys beyond the envelope are the frame type's own, for its table to
40/// judge.
41pub fn read_envelope(v: &Value) -> Result<Envelope, FrameError> {
42    let Value::Map(pairs) = v else {
43        return Err(FrameError::Malformed);
44    };
45    let mut frame_type = None;
46    let mut has_version = false;
47    let mut kept = Vec::with_capacity(pairs.len());
48    for (key, value) in pairs {
49        let Value::Text(name) = key else {
50            return Err(FrameError::Malformed);
51        };
52        match name.as_str() {
53            "version" if *value == Value::Int(i128::from(PROTOCOL_VERSION)) => has_version = true,
54            "frame_type" => match value {
55                Value::Text(t) if !t.is_empty() && t.len() <= MAX_FRAME_TYPE_BYTES => {
56                    frame_type = Some(t.clone())
57                }
58                _ => return Err(FrameError::Malformed),
59            },
60            "ext" => {
61                act_on_ext(value)?;
62                continue;
63            }
64            "version" | "capabilities" => return Err(FrameError::Malformed),
65            other if !shared_key_accepts(other, value) => return Err(FrameError::Malformed),
66            _ => {}
67        }
68        kept.push((key.clone(), value.clone()));
69    }
70    match (has_version, frame_type) {
71        (true, Some(frame_type)) => Ok(Envelope {
72            frame_type,
73            frame: Value::Map(kept),
74        }),
75        _ => Err(FrameError::Malformed),
76    }
77}
78
79/// The frame type of a frame that reads as an envelope but is of a type
80/// outside `known`: counted, never acted on, never forwarded. `None` for a
81/// known type.
82pub fn unknown_frame_type(envelope: &Envelope, known: &[&str]) -> Option<String> {
83    if known.contains(&envelope.frame_type.as_str()) {
84        return None;
85    }
86    count_unknown_frame_type();
87    Some(envelope.frame_type.clone())
88}
89
90/// Whether a shared envelope key's value is of its type; a key that is not
91/// one of them is the frame type's own.
92fn shared_key_accepts(name: &str, v: &Value) -> bool {
93    match name {
94        "frame_id" => matches!(v, Value::Bytes(b) if b.len() == 16),
95        "sent_at_ms" => protocol_uint(v).is_some(),
96        "realm" => matches!(v, Value::Bytes(b) if b.len() == 32),
97        "call_id" => matches!(v, Value::Bytes(b) if b.len() == 16),
98        "source_route" => matches!(v, Value::Bytes(_)),
99        _ => true,
100    }
101}
102
103/// Judges an `ext` map's shape alone (WIRE_1_0.md section 3.2): 1 to 16
104/// entries, each a name of 1 to 64 bytes of `[a-z0-9_.]` mapped to exactly
105/// `{critical: 0 | 1, value}`, else [`FrameError::Malformed`]. It acts on
106/// nothing, as a custodian storing a record that carries `ext` does not.
107pub fn check_ext(v: &Value) -> Result<(), FrameError> {
108    ext_entries(v).map(|_| ())
109}
110
111/// Acts on a well-formed `ext` map as a receiver that knows no extension: an
112/// unknown critical one is [`FrameError::ExtensionUnsupported`], each such
113/// name counted as `wire_ext_refused`; only when none is, each unknown
114/// non-critical one is counted under its name as `wire_ext_ignored`.
115pub fn act_on_ext(v: &Value) -> Result<(), FrameError> {
116    let entries = ext_entries(v)?;
117    let refused: Vec<&String> = entries
118        .iter()
119        .filter(|(name, critical)| *critical && !KNOWN_EXTENSIONS.contains(&name.as_str()))
120        .map(|(name, _)| name)
121        .collect();
122    if let Some(first) = refused.first() {
123        refused.iter().for_each(|name| count_ext_refused(name));
124        return Err(FrameError::ExtensionUnsupported((*first).clone()));
125    }
126    for (name, _) in entries
127        .iter()
128        .filter(|(name, _)| !KNOWN_EXTENSIONS.contains(&name.as_str()))
129    {
130        count_ext_ignored(name);
131    }
132    Ok(())
133}
134
135/// A well-formed `ext` map's entries, name and whether it is critical.
136fn ext_entries(v: &Value) -> Result<Vec<(String, bool)>, FrameError> {
137    let Value::Map(pairs) = v else {
138        return Err(FrameError::Malformed);
139    };
140    if pairs.is_empty() || pairs.len() > MAX_EXTENSIONS {
141        return Err(FrameError::Malformed);
142    }
143    pairs
144        .iter()
145        .map(|(key, entry)| match (key, extension_critical(entry)) {
146            (Value::Text(name), Some(critical)) if extension_name(name) => {
147                Ok((name.clone(), critical))
148            }
149            _ => Err(FrameError::Malformed),
150        })
151        .collect()
152}
153
154/// An extension entry's `critical`, when it is exactly `{critical: 0 | 1,
155/// value}`.
156fn extension_critical(entry: &Value) -> Option<bool> {
157    let Value::Map(fields) = entry else {
158        return None;
159    };
160    let named = |n: &str| fields.iter().filter(|(k, _)| *k == Value::text(n)).count() == 1;
161    if fields.len() != 2 || !named("critical") || !named("value") {
162        return None;
163    }
164    match entry.get("critical") {
165        Some(Value::Int(0)) => Some(false),
166        Some(Value::Int(1)) => Some(true),
167        _ => None,
168    }
169}
170
171fn extension_name(name: &str) -> bool {
172    !name.is_empty()
173        && name.len() <= MAX_EXTENSION_NAME_BYTES
174        && name
175            .bytes()
176            .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == b'_' || c == b'.')
177}