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 super::Error;
28 use super::Result;
29
30 use crate::h3::Header;
31
32 use super::INDEXED;
33 use super::INDEXED_WITH_POST_BASE;
34 use super::LITERAL;
35 use super::LITERAL_WITH_NAME_REF;
36
37 #[derive(Clone, Copy, Debug, PartialEq)]
38 enum Representation {
39 Indexed,
40 IndexedWithPostBase,
41 Literal,
42 LiteralWithNameRef,
43 LiteralWithPostBase,
44 }
45
46 impl Representation {
from_byte(b: u8) -> Representation47 pub fn from_byte(b: u8) -> Representation {
48 if b & INDEXED == INDEXED {
49 return Representation::Indexed;
50 }
51
52 if b & LITERAL_WITH_NAME_REF == LITERAL_WITH_NAME_REF {
53 return Representation::LiteralWithNameRef;
54 }
55
56 if b & LITERAL == LITERAL {
57 return Representation::Literal;
58 }
59
60 if b & INDEXED_WITH_POST_BASE == INDEXED_WITH_POST_BASE {
61 return Representation::IndexedWithPostBase;
62 }
63
64 Representation::LiteralWithPostBase
65 }
66 }
67
68 /// A QPACK decoder.
69 #[derive(Default)]
70 pub struct Decoder {}
71
72 impl Decoder {
73 /// Creates a new QPACK decoder.
new() -> Decoder74 pub fn new() -> Decoder {
75 Decoder::default()
76 }
77
78 /// Processes control instructions from the encoder.
control(&mut self, _buf: &mut [u8]) -> Result<()>79 pub fn control(&mut self, _buf: &mut [u8]) -> Result<()> {
80 // TODO: process control instructions
81 Ok(())
82 }
83
84 /// Decodes a QPACK header block into a list of headers.
decode(&mut self, buf: &[u8], max_size: u64) -> Result<Vec<Header>>85 pub fn decode(&mut self, buf: &[u8], max_size: u64) -> Result<Vec<Header>> {
86 let mut b = octets::Octets::with_slice(buf);
87
88 let mut out = Vec::new();
89
90 let mut left = max_size;
91
92 let req_insert_count = decode_int(&mut b, 8)?;
93 let base = decode_int(&mut b, 7)?;
94
95 trace!("Header count={} base={}", req_insert_count, base);
96
97 while b.cap() > 0 {
98 let first = b.peek_u8()?;
99
100 match Representation::from_byte(first) {
101 Representation::Indexed => {
102 const STATIC: u8 = 0x40;
103
104 let s = first & STATIC == STATIC;
105 let index = decode_int(&mut b, 6)?;
106
107 trace!("Indexed index={} static={}", index, s);
108
109 if !s {
110 // TODO: implement dynamic table
111 return Err(Error::InvalidHeaderValue);
112 }
113
114 let (name, value) = lookup_static(index)?;
115
116 left = left
117 .checked_sub((name.len() + value.len()) as u64)
118 .ok_or(Error::HeaderListTooLarge)?;
119
120 let hdr = Header::new(name, value);
121 out.push(hdr);
122 },
123
124 Representation::IndexedWithPostBase => {
125 let index = decode_int(&mut b, 4)?;
126
127 trace!("Indexed With Post Base index={}", index);
128
129 // TODO: implement dynamic table
130 return Err(Error::InvalidHeaderValue);
131 },
132
133 Representation::Literal => {
134 let name_huff = b.as_ref()[0] & 0x08 == 0x08;
135 let name_len = decode_int(&mut b, 3)? as usize;
136
137 let mut name = b.get_bytes(name_len)?;
138
139 let name = if name_huff {
140 super::huffman::decode(&mut name)?
141 } else {
142 name.to_vec()
143 };
144
145 let name = name.to_vec();
146 let value = decode_str(&mut b)?;
147
148 trace!(
149 "Literal Without Name Reference name={:?} value={:?}",
150 name,
151 value,
152 );
153
154 left = left
155 .checked_sub((name.len() + value.len()) as u64)
156 .ok_or(Error::HeaderListTooLarge)?;
157
158 // Instead of calling Header::new(), create Header directly
159 // from `name` and `value`, which are already String.
160 let hdr = Header(name, value);
161 out.push(hdr);
162 },
163
164 Representation::LiteralWithNameRef => {
165 const STATIC: u8 = 0x10;
166
167 let s = first & STATIC == STATIC;
168 let name_idx = decode_int(&mut b, 4)?;
169 let value = decode_str(&mut b)?;
170
171 trace!(
172 "Literal name_idx={} static={} value={:?}",
173 name_idx,
174 s,
175 value
176 );
177
178 if !s {
179 // TODO: implement dynamic table
180 return Err(Error::InvalidHeaderValue);
181 }
182
183 let (name, _) = lookup_static(name_idx)?;
184
185 left = left
186 .checked_sub((name.len() + value.len()) as u64)
187 .ok_or(Error::HeaderListTooLarge)?;
188
189 // Instead of calling Header::new(), create Header directly
190 // from `value`, which is already String, but clone `name`
191 // as it is just a reference.
192 let hdr = Header(name.to_vec(), value);
193 out.push(hdr);
194 },
195
196 Representation::LiteralWithPostBase => {
197 trace!("Literal With Post Base");
198
199 // TODO: implement dynamic table
200 return Err(Error::InvalidHeaderValue);
201 },
202 }
203 }
204
205 Ok(out)
206 }
207 }
208
lookup_static(idx: u64) -> Result<(&'static [u8], &'static [u8])>209 fn lookup_static(idx: u64) -> Result<(&'static [u8], &'static [u8])> {
210 if idx >= super::static_table::STATIC_TABLE.len() as u64 {
211 return Err(Error::InvalidStaticTableIndex);
212 }
213
214 Ok(super::static_table::STATIC_TABLE[idx as usize])
215 }
216
decode_int(b: &mut octets::Octets, prefix: usize) -> Result<u64>217 fn decode_int(b: &mut octets::Octets, prefix: usize) -> Result<u64> {
218 let mask = 2u64.pow(prefix as u32) - 1;
219
220 let mut val = u64::from(b.get_u8()?);
221 val &= mask;
222
223 if val < mask {
224 return Ok(val);
225 }
226
227 let mut shift = 0;
228
229 while b.cap() > 0 {
230 let byte = b.get_u8()?;
231
232 let inc = u64::from(byte & 0x7f)
233 .checked_shl(shift)
234 .ok_or(Error::BufferTooShort)?;
235
236 val = val.checked_add(inc).ok_or(Error::BufferTooShort)?;
237
238 shift += 7;
239
240 if byte & 0x80 == 0 {
241 return Ok(val);
242 }
243 }
244
245 Err(Error::BufferTooShort)
246 }
247
decode_str(b: &mut octets::Octets) -> Result<Vec<u8>>248 fn decode_str(b: &mut octets::Octets) -> Result<Vec<u8>> {
249 let first = b.peek_u8()?;
250
251 let huff = first & 0x80 == 0x80;
252
253 let len = decode_int(b, 7)? as usize;
254
255 let mut val = b.get_bytes(len)?;
256
257 let val = if huff {
258 super::huffman::decode(&mut val)?
259 } else {
260 val.to_vec()
261 };
262
263 Ok(val)
264 }
265
266 #[cfg(test)]
267 mod tests {
268 use super::*;
269
270 #[test]
decode_int1()271 fn decode_int1() {
272 let mut encoded = [0b01010, 0x02];
273 let mut b = octets::Octets::with_slice(&mut encoded);
274
275 assert_eq!(decode_int(&mut b, 5), Ok(10));
276 }
277
278 #[test]
decode_int2()279 fn decode_int2() {
280 let mut encoded = [0b11111, 0b10011010, 0b00001010];
281 let mut b = octets::Octets::with_slice(&mut encoded);
282
283 assert_eq!(decode_int(&mut b, 5), Ok(1337));
284 }
285
286 #[test]
decode_int3()287 fn decode_int3() {
288 let mut encoded = [0b101010];
289 let mut b = octets::Octets::with_slice(&mut encoded);
290
291 assert_eq!(decode_int(&mut b, 8), Ok(42));
292 }
293 }
294