1 // Copyright (C) 2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 use crate::octets;
28
29 use super::Error;
30 use super::Result;
31
32 use crate::h3::Header;
33
34 use super::INDEXED;
35 use super::INDEXED_WITH_POST_BASE;
36 use super::LITERAL;
37 use super::LITERAL_WITH_NAME_REF;
38
39 #[derive(Clone, Copy, Debug, PartialEq)]
40 enum Representation {
41 Indexed,
42 IndexedWithPostBase,
43 Literal,
44 LiteralWithNameRef,
45 LiteralWithPostBase,
46 }
47
48 impl Representation {
from_byte(b: u8) -> Representation49 pub fn from_byte(b: u8) -> Representation {
50 if b & INDEXED == INDEXED {
51 return Representation::Indexed;
52 }
53
54 if b & LITERAL_WITH_NAME_REF == LITERAL_WITH_NAME_REF {
55 return Representation::LiteralWithNameRef;
56 }
57
58 if b & LITERAL == LITERAL {
59 return Representation::Literal;
60 }
61
62 if b & INDEXED_WITH_POST_BASE == INDEXED_WITH_POST_BASE {
63 return Representation::IndexedWithPostBase;
64 }
65
66 Representation::LiteralWithPostBase
67 }
68 }
69
70 /// A QPACK decoder.
71 pub struct Decoder {}
72
73 impl Default for Decoder {
default() -> Decoder74 fn default() -> Decoder {
75 Decoder {}
76 }
77 }
78
79 impl Decoder {
80 /// Creates a new QPACK decoder.
new() -> Decoder81 pub fn new() -> Decoder {
82 Decoder::default()
83 }
84
85 /// Processes control instructions from the encoder.
control(&mut self, _buf: &mut [u8]) -> Result<()>86 pub fn control(&mut self, _buf: &mut [u8]) -> Result<()> {
87 // TODO: process control instructions
88 Ok(())
89 }
90
91 /// Decodes a QPACK header block into a list of headers.
decode(&mut self, buf: &[u8], max_size: u64) -> Result<Vec<Header>>92 pub fn decode(&mut self, buf: &[u8], max_size: u64) -> Result<Vec<Header>> {
93 let mut b = octets::Octets::with_slice(buf);
94
95 let mut out = Vec::new();
96
97 let mut left = max_size;
98
99 let req_insert_count = decode_int(&mut b, 8)?;
100 let base = decode_int(&mut b, 7)?;
101
102 trace!("Header count={} base={}", req_insert_count, base);
103
104 while b.cap() > 0 {
105 let first = b.peek_u8()?;
106
107 match Representation::from_byte(first) {
108 Representation::Indexed => {
109 const STATIC: u8 = 0x40;
110
111 let s = first & STATIC == STATIC;
112 let index = decode_int(&mut b, 6)?;
113
114 trace!("Indexed index={} static={}", index, s);
115
116 if !s {
117 // TODO: implement dynamic table
118 return Err(Error::InvalidHeaderValue);
119 }
120
121 let (name, value) = lookup_static(index)?;
122
123 left = left
124 .checked_sub((name.len() + value.len()) as u64)
125 .ok_or(Error::HeaderListTooLarge)?;
126
127 let hdr = Header::new(name, value);
128 out.push(hdr);
129 },
130
131 Representation::IndexedWithPostBase => {
132 let index = decode_int(&mut b, 4)?;
133
134 trace!("Indexed With Post Base index={}", index);
135
136 // TODO: implement dynamic table
137 return Err(Error::InvalidHeaderValue);
138 },
139
140 Representation::Literal => {
141 let name_huff = b.as_ref()[0] & 0x08 == 0x08;
142 let name_len = decode_int(&mut b, 3)? as usize;
143
144 let mut name = b.get_bytes(name_len)?;
145
146 let name = if name_huff {
147 super::huffman::decode(&mut name)?
148 } else {
149 name.to_vec()
150 };
151
152 let name = String::from_utf8(name)
153 .map_err(|_| Error::InvalidHeaderValue)?;
154
155 let value = decode_str(&mut b)?;
156
157 trace!(
158 "Literal Without Name Reference name={:?} value={:?}",
159 name,
160 value,
161 );
162
163 left = left
164 .checked_sub((name.len() + value.len()) as u64)
165 .ok_or(Error::HeaderListTooLarge)?;
166
167 // Instead of calling Header::new(), create Header directly
168 // from `name` and `value`, which are already String.
169 let hdr = Header(name, value);
170 out.push(hdr);
171 },
172
173 Representation::LiteralWithNameRef => {
174 const STATIC: u8 = 0x10;
175
176 let s = first & STATIC == STATIC;
177 let name_idx = decode_int(&mut b, 4)?;
178 let value = decode_str(&mut b)?;
179
180 trace!(
181 "Literal name_idx={} static={} value={:?}",
182 name_idx,
183 s,
184 value
185 );
186
187 if !s {
188 // TODO: implement dynamic table
189 return Err(Error::InvalidHeaderValue);
190 }
191
192 let (name, _) = lookup_static(name_idx)?;
193
194 left = left
195 .checked_sub((name.len() + value.len()) as u64)
196 .ok_or(Error::HeaderListTooLarge)?;
197
198 // Instead of calling Header::new(), create Header directly
199 // from `value`, which is already String, but clone `name`
200 // as it is just a reference.
201 let hdr = Header(name.to_string(), value);
202 out.push(hdr);
203 },
204
205 Representation::LiteralWithPostBase => {
206 trace!("Literal With Post Base");
207
208 // TODO: implement dynamic table
209 return Err(Error::InvalidHeaderValue);
210 },
211 }
212 }
213
214 Ok(out)
215 }
216 }
217
lookup_static(idx: u64) -> Result<(&'static str, &'static str)>218 fn lookup_static(idx: u64) -> Result<(&'static str, &'static str)> {
219 if idx >= super::static_table::STATIC_TABLE.len() as u64 {
220 return Err(Error::InvalidStaticTableIndex);
221 }
222
223 Ok(super::static_table::STATIC_TABLE[idx as usize])
224 }
225
decode_int(b: &mut octets::Octets, prefix: usize) -> Result<u64>226 fn decode_int(b: &mut octets::Octets, prefix: usize) -> Result<u64> {
227 let mask = 2u64.pow(prefix as u32) - 1;
228
229 let mut val = u64::from(b.get_u8()?);
230 val &= mask;
231
232 if val < mask {
233 return Ok(val);
234 }
235
236 let mut shift = 0;
237
238 while b.cap() > 0 {
239 let byte = b.get_u8()?;
240
241 let inc = u64::from(byte & 0x7f)
242 .checked_shl(shift)
243 .ok_or(Error::BufferTooShort)?;
244
245 val = val.checked_add(inc).ok_or(Error::BufferTooShort)?;
246
247 shift += 7;
248
249 if byte & 0x80 == 0 {
250 return Ok(val);
251 }
252 }
253
254 Err(Error::BufferTooShort)
255 }
256
decode_str<'a>(b: &'a mut octets::Octets) -> Result<String>257 fn decode_str<'a>(b: &'a mut octets::Octets) -> Result<String> {
258 let first = b.peek_u8()?;
259
260 let huff = first & 0x80 == 0x80;
261
262 let len = decode_int(b, 7)? as usize;
263
264 let mut val = b.get_bytes(len)?;
265
266 let val = if huff {
267 super::huffman::decode(&mut val)?
268 } else {
269 val.to_vec()
270 };
271
272 let val = String::from_utf8(val).map_err(|_| Error::InvalidHeaderValue)?;
273 Ok(val)
274 }
275
276 #[cfg(test)]
277 mod tests {
278 use super::*;
279
280 use crate::octets;
281
282 #[test]
decode_int1()283 fn decode_int1() {
284 let mut encoded = [0b01010, 0x02];
285 let mut b = octets::Octets::with_slice(&mut encoded);
286
287 assert_eq!(decode_int(&mut b, 5), Ok(10));
288 }
289
290 #[test]
decode_int2()291 fn decode_int2() {
292 let mut encoded = [0b11111, 0b10011010, 0b00001010];
293 let mut b = octets::Octets::with_slice(&mut encoded);
294
295 assert_eq!(decode_int(&mut b, 5), Ok(1337));
296 }
297
298 #[test]
decode_int3()299 fn decode_int3() {
300 let mut encoded = [0b101010];
301 let mut b = octets::Octets::with_slice(&mut encoded);
302
303 assert_eq!(decode_int(&mut b, 8), Ok(42));
304 }
305 }
306