quiche/h3/qpack/
encoder.rs1use super::Result;
28
29use crate::h3::NameValue;
30
31use super::INDEXED;
32use super::LITERAL;
33use super::LITERAL_WITH_NAME_REF;
34
35#[derive(Default)]
37pub struct Encoder {}
38
39impl Encoder {
40 pub fn new() -> Encoder {
42 Encoder::default()
43 }
44
45 pub fn encode<T: NameValue>(
47 &mut self, headers: &[T], out: &mut [u8],
48 ) -> Result<usize> {
49 let mut b = octets::OctetsMut::with_slice(out);
50
51 encode_int(0, 0, 8, &mut b)?;
53
54 encode_int(0, 0, 7, &mut b)?;
56
57 for h in headers {
58 match lookup_static(h) {
59 Some((idx, true)) => {
60 const STATIC: u8 = 0x40;
61
62 encode_int(idx, INDEXED | STATIC, 6, &mut b)?;
64 },
65
66 Some((idx, false)) => {
67 const STATIC: u8 = 0x10;
68
69 encode_int(idx, LITERAL_WITH_NAME_REF | STATIC, 4, &mut b)?;
71 encode_str::<false>(h.value(), 0, 7, &mut b)?;
72 },
73
74 None => {
75 encode_str::<true>(h.name(), LITERAL, 3, &mut b)?;
78 encode_str::<false>(h.value(), 0, 7, &mut b)?;
79 },
80 };
81 }
82
83 Ok(b.off())
84 }
85}
86
87fn lookup_static<T: NameValue>(h: &T) -> Option<(u64, bool)> {
88 let table_for_len =
90 super::static_table::STATIC_ENCODE_TABLE.get(h.name().len())?;
91
92 let cmp_lowercase = |a: &[u8], b: &[u8]| {
95 std::iter::zip(a, b).all(|(a, b)| a.eq(&b.to_ascii_lowercase()))
96 };
97
98 for (name, values) in table_for_len.iter() {
99 if cmp_lowercase(name, h.name()) {
101 for (value, enc) in values.iter() {
103 if value.is_empty() {
105 return Some((*enc, false));
106 }
107
108 if h.value() == *value {
109 return Some((*enc, true));
110 }
111 }
112 return Some((values.first()?.1, false));
114 }
115 }
116
117 None
118}
119
120pub fn encode_int(
121 mut v: u64, first: u8, prefix: usize, b: &mut octets::OctetsMut,
122) -> Result<()> {
123 let mask = 2u64.pow(prefix as u32) - 1;
124
125 if v < mask {
127 b.put_u8(first | v as u8)?;
128 return Ok(());
129 }
130
131 b.put_u8(first | mask as u8)?;
133
134 v -= mask;
135
136 while v >= 128 {
137 b.put_u8((v % 128 + 128) as u8)?;
139
140 v >>= 7;
141 }
142
143 b.put_u8(v as u8)?;
145
146 Ok(())
147}
148
149#[inline]
150pub fn encode_str<const LOWER_CASE: bool>(
151 v: &[u8], first: u8, prefix: usize, b: &mut octets::OctetsMut,
152) -> Result<()> {
153 match octets::huffman_encoding_len::<LOWER_CASE>(v) {
156 Ok(len) => {
157 encode_int(len as u64, first | (1 << prefix), prefix, b)?;
158 b.put_huffman_encoded::<LOWER_CASE>(v)?;
159 },
160
161 Err(_) => {
162 encode_int(v.len() as u64, first, prefix, b)?;
163 if LOWER_CASE {
164 b.put_bytes(&v.to_ascii_lowercase())?;
165 } else {
166 b.put_bytes(v)?;
167 }
168 },
169 }
170
171 Ok(())
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn encode_int1() {
180 let expected = [0b01010];
181 let mut encoded = [0; 1];
182 let mut b = octets::OctetsMut::with_slice(&mut encoded);
183
184 assert!(encode_int(10, 0, 5, &mut b).is_ok());
185
186 assert_eq!(expected, encoded);
187 }
188
189 #[test]
190 fn encode_int2() {
191 let expected = [0b11111, 0b10011010, 0b00001010];
192 let mut encoded = [0; 3];
193 let mut b = octets::OctetsMut::with_slice(&mut encoded);
194
195 assert!(encode_int(1337, 0, 5, &mut b).is_ok());
196
197 assert_eq!(expected, encoded);
198 }
199
200 #[test]
201 fn encode_int3() {
202 let expected = [0b101010];
203 let mut encoded = [0; 1];
204 let mut b = octets::OctetsMut::with_slice(&mut encoded);
205
206 assert!(encode_int(42, 0, 8, &mut b).is_ok());
207
208 assert_eq!(expected, encoded);
209 }
210
211 #[test]
212 fn encode_static_header() {
213 let mut encoded = [0; 3];
214 Encoder::default()
215 .encode(&[(b":method", b"GET")], &mut encoded)
216 .unwrap();
217 assert_eq!(encoded, [0, 0, INDEXED | 0x40 | 17]);
218 }
219
220 #[test]
221 fn encode_static_header_name_only() {
222 let mut encoded = [0; 11];
223 let mut expected = [0; 11];
224 let mut buf = octets::OctetsMut::with_slice(&mut expected[..]);
225 buf.put_u16(0).unwrap();
226 buf.put_u8(LITERAL_WITH_NAME_REF | 0x10 | 15).unwrap();
227 buf.put_u8(0).unwrap();
228 encode_str::<false>(b"FORGET", 0, 7, &mut buf).unwrap();
229
230 Encoder::default()
231 .encode(&[(b":method", b"FORGET")], &mut encoded)
232 .unwrap();
233 assert_eq!(encoded, expected);
234 }
235}