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}