Skip to main content

moqtap_codec/
kvp.rs

1use crate::varint::VarInt;
2use bytes::{Buf, BufMut};
3
4#[inline]
5#[allow(clippy::uninit_vec)]
6fn read_bytes_kvp(buf: &mut impl Buf, len: usize) -> Result<Vec<u8>, KvpError> {
7    if buf.remaining() < len {
8        return Err(KvpError::UnexpectedEnd);
9    }
10    let mut v = Vec::with_capacity(len);
11    // Safety: set_len(len) then overwrite all `len` bytes via copy_to_slice.
12    unsafe {
13        v.set_len(len);
14    }
15    buf.copy_to_slice(&mut v);
16    Ok(v)
17}
18
19/// Maximum value length for a Key-Value Pair: 2^16 - 1 bytes.
20///
21/// Drafts 11 through 15 state it of the Key-Value-Pair Length field: "The
22/// maximum length of a value is 2^16-1 bytes. If an endpoint receives a length
23/// larger than the maximum, it MUST close the session with a Protocol
24/// Violation." Drafts 16 and later spell the code `PROTOCOL_VIOLATION` and
25/// change nothing else. It is a receiver's rule, which is why it is applied
26/// when decoding.
27///
28/// Drafts 07 through 10 have no Key-Value-Pair. They carry a Parameter with an
29/// unbounded length and state no maximum, so [`KeyValuePair::decode_d07`] does
30/// not apply this.
31pub const MAX_KVP_VALUE_LEN: usize = 65535;
32
33/// Value of a Key-Value Pair.
34/// Even key type -> varint value (no length field).
35/// Odd key type -> length-prefixed bytes.
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum KvpValue {
38    /// Varint value (used with even key types).
39    Varint(VarInt),
40    /// Length-prefixed byte string (used with odd key types).
41    Bytes(Vec<u8>),
42}
43
44/// A MoQT Key-Value Pair (used for parameters in control messages).
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct KeyValuePair {
47    /// Parameter key (even = varint value, odd = byte string value).
48    pub key: VarInt,
49    /// Parameter value.
50    pub value: KvpValue,
51}
52
53/// Errors produced when encoding or decoding key-value pairs.
54#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
55pub enum KvpError {
56    /// Odd key type was not followed by a length-prefixed value.
57    #[error("odd key type requires length-prefixed value")]
58    MissingLength,
59    /// Value length exceeds [`MAX_KVP_VALUE_LEN`].
60    #[error("value length {0} exceeds maximum ({MAX_KVP_VALUE_LEN})")]
61    ValueTooLong(usize),
62    /// Not enough bytes in the buffer to complete decoding.
63    #[error("insufficient bytes")]
64    UnexpectedEnd,
65    /// Variable-length integer encoding/decoding error.
66    #[error("varint error: {0}")]
67    VarInt(#[from] crate::varint::VarIntError),
68}
69
70impl KeyValuePair {
71    /// Encode a single key-value pair.
72    pub fn encode(&self, buf: &mut impl BufMut) {
73        self.key.encode(buf);
74        match &self.value {
75            KvpValue::Varint(v) => {
76                // Even key: write varint value directly
77                v.encode(buf);
78            }
79            KvpValue::Bytes(bytes) => {
80                // Odd key: write length-prefixed bytes
81                VarInt::from_usize(bytes.len()).encode(buf);
82                buf.put_slice(bytes);
83            }
84        }
85    }
86
87    /// Decode a single key-value pair.
88    pub fn decode(buf: &mut impl Buf) -> Result<Self, KvpError> {
89        let key = VarInt::decode(buf)?;
90        let key_val = key.into_inner();
91
92        if key_val.is_multiple_of(2) {
93            // Even key: value is a varint
94            let value = VarInt::decode(buf)?;
95            Ok(KeyValuePair { key, value: KvpValue::Varint(value) })
96        } else {
97            // Odd key: value is length-prefixed bytes
98            let len = VarInt::decode(buf)?.into_inner() as usize;
99            if len > MAX_KVP_VALUE_LEN {
100                return Err(KvpError::ValueTooLong(len));
101            }
102            let bytes = read_bytes_kvp(buf, len)?;
103            Ok(KeyValuePair { key, value: KvpValue::Bytes(bytes) })
104        }
105    }
106
107    /// The half of [`Self::encode_list_checked`] that does not write, so a list
108    /// can check every pair before committing any of them.
109    fn check_value_len(&self) -> Result<(), KvpError> {
110        if let KvpValue::Bytes(bytes) = &self.value {
111            if bytes.len() > MAX_KVP_VALUE_LEN {
112                return Err(KvpError::ValueTooLong(bytes.len()));
113            }
114        }
115        Ok(())
116    }
117
118    /// Encode a list of key-value pairs (count-prefixed).
119    pub fn encode_list(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
120        VarInt::from_usize(pairs.len()).encode(buf);
121        for pair in pairs {
122            pair.encode(buf);
123        }
124    }
125
126    /// Encode a count-prefixed list, refusing a value no peer may accept.
127    ///
128    /// [`Self::encode_list`] writes whatever it is given. The length maximum in
129    /// [`MAX_KVP_VALUE_LEN`] is written as a receiver's rule, and it is applied
130    /// on decode for that reason — but a value past it is one the receiver is
131    /// required to close the session over, so writing it is not a way to send
132    /// it. This is the entry point that says so before any byte is written, and
133    /// it is what the parameter encoders of drafts 11 through 15 write through.
134    ///
135    /// Every pair is checked before the first is written, so a refused list
136    /// leaves `buf` untouched rather than half a list followed by an error.
137    ///
138    /// **The refusal is never the only one.** Those drafts also limit a control
139    /// message to 2^16-1 bytes, and the two maxima are the same number, so a
140    /// value one byte past this one is already inside a payload one byte past
141    /// that one. What this adds is which of the two rules the error names, at
142    /// the layer that owns it, rather than whether the message is written.
143    ///
144    /// Drafts 07 through 10 have no Key-Value-Pair and state no maximum; their
145    /// [`Self::encode_list_d07`] is unaffected and stays infallible.
146    pub fn encode_list_checked(
147        pairs: &[KeyValuePair],
148        buf: &mut impl BufMut,
149    ) -> Result<(), KvpError> {
150        for pair in pairs {
151            pair.check_value_len()?;
152        }
153        Self::encode_list(pairs, buf);
154        Ok(())
155    }
156
157    /// Decode a list of key-value pairs (count-prefixed).
158    pub fn decode_list(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, KvpError> {
159        let count = VarInt::decode(buf)?.into_inner() as usize;
160        let mut pairs = crate::types::reserve_bounded(count, buf);
161        for _ in 0..count {
162            pairs.push(KeyValuePair::decode(buf)?);
163        }
164        Ok(pairs)
165    }
166
167    /// Decode a single Parameter using the drafts 07 through 10 format, where
168    /// every value is length-prefixed.
169    ///
170    /// No cap is applied to the length. Those four drafts describe a Parameter
171    /// as `{ Parameter Type (i), Parameter Length (i), Parameter Value (..) }`
172    /// and say nothing about how long a value may be; the 2^16-1 maximum in
173    /// [`MAX_KVP_VALUE_LEN`] arrives with the Key-Value-Pair of draft-11, and
174    /// applying it here refuses parameters these drafts permit.
175    ///
176    /// The read is still bounded: the reader refuses a length longer than the
177    /// bytes actually present, so a declared length cannot make this allocate
178    /// more than the peer really sent.
179    pub fn decode_d07(buf: &mut impl Buf) -> Result<Self, KvpError> {
180        let key = VarInt::decode(buf)?;
181        let len = VarInt::decode(buf)?.into_inner() as usize;
182        let bytes = read_bytes_kvp(buf, len)?;
183        Ok(KeyValuePair { key, value: KvpValue::Bytes(bytes) })
184    }
185
186    /// Encode a single KVP using draft-07 format (all values are length-prefixed).
187    pub fn encode_d07(&self, buf: &mut impl BufMut) {
188        self.key.encode(buf);
189        match &self.value {
190            KvpValue::Varint(v) => {
191                VarInt::from_usize(v.encoded_len()).encode(buf);
192                v.encode(buf);
193            }
194            KvpValue::Bytes(bytes) => {
195                VarInt::from_usize(bytes.len()).encode(buf);
196                buf.put_slice(bytes);
197            }
198        }
199    }
200
201    /// Decode a list of KVPs using draft-07 format.
202    pub fn decode_list_d07(buf: &mut impl Buf) -> Result<Vec<KeyValuePair>, KvpError> {
203        let count = VarInt::decode(buf)?.into_inner() as usize;
204        let mut pairs = crate::types::reserve_bounded(count, buf);
205        for _ in 0..count {
206            pairs.push(KeyValuePair::decode_d07(buf)?);
207        }
208        Ok(pairs)
209    }
210
211    /// Encode a list of KVPs using draft-07 format.
212    pub fn encode_list_d07(pairs: &[KeyValuePair], buf: &mut impl BufMut) {
213        VarInt::from_usize(pairs.len()).encode(buf);
214        for pair in pairs {
215            pair.encode_d07(buf);
216        }
217    }
218
219    // No MoQT-varint form of a Key-Value-Pair lives here, and the drafts are why.
220    //
221    // Every draft that reaches for the MoQT varint delta-codes the parameter
222    // type: it writes the difference from the previous type rather than the type
223    // itself, which makes a pair unreadable outside the list it sits in and a
224    // list unreadable outside the message. So the unit these drafts serialize is
225    // the list-in-a-message, not the pair, and each of them serializes it in its
226    // own module — drafts 17, 18 and 19 with two rules for the value shape, one
227    // reading a table and one reading the type's parity, in two parameter
228    // namespaces that do not agree.
229    //
230    // A pair-at-a-time encoder over the MoQT varint would have to write the type
231    // absolutely to be callable at all, and no draft reads that.
232}