/rust/registry/src/index.crates.io-6f17d22bba15001f/h2-0.3.26/src/hpack/decoder.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use super::{header::BytesStr, huffman, Header}; |
2 | | use crate::frame; |
3 | | |
4 | | use bytes::{Buf, Bytes, BytesMut}; |
5 | | use http::header; |
6 | | use http::method::{self, Method}; |
7 | | use http::status::{self, StatusCode}; |
8 | | |
9 | | use std::cmp; |
10 | | use std::collections::VecDeque; |
11 | | use std::io::Cursor; |
12 | | use std::str::Utf8Error; |
13 | | |
14 | | /// Decodes headers using HPACK |
15 | | #[derive(Debug)] |
16 | | pub struct Decoder { |
17 | | // Protocol indicated that the max table size will update |
18 | | max_size_update: Option<usize>, |
19 | | last_max_update: usize, |
20 | | table: Table, |
21 | | buffer: BytesMut, |
22 | | } |
23 | | |
24 | | /// Represents all errors that can be encountered while performing the decoding |
25 | | /// of an HPACK header set. |
26 | | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
27 | | pub enum DecoderError { |
28 | | InvalidRepresentation, |
29 | | InvalidIntegerPrefix, |
30 | | InvalidTableIndex, |
31 | | InvalidHuffmanCode, |
32 | | InvalidUtf8, |
33 | | InvalidStatusCode, |
34 | | InvalidPseudoheader, |
35 | | InvalidMaxDynamicSize, |
36 | | IntegerOverflow, |
37 | | NeedMore(NeedMore), |
38 | | } |
39 | | |
40 | | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
41 | | pub enum NeedMore { |
42 | | UnexpectedEndOfStream, |
43 | | IntegerUnderflow, |
44 | | StringUnderflow, |
45 | | } |
46 | | |
47 | | enum Representation { |
48 | | /// Indexed header field representation |
49 | | /// |
50 | | /// An indexed header field representation identifies an entry in either the |
51 | | /// static table or the dynamic table (see Section 2.3). |
52 | | /// |
53 | | /// # Header encoding |
54 | | /// |
55 | | /// ```text |
56 | | /// 0 1 2 3 4 5 6 7 |
57 | | /// +---+---+---+---+---+---+---+---+ |
58 | | /// | 1 | Index (7+) | |
59 | | /// +---+---------------------------+ |
60 | | /// ``` |
61 | | Indexed, |
62 | | |
63 | | /// Literal Header Field with Incremental Indexing |
64 | | /// |
65 | | /// A literal header field with incremental indexing representation results |
66 | | /// in appending a header field to the decoded header list and inserting it |
67 | | /// as a new entry into the dynamic table. |
68 | | /// |
69 | | /// # Header encoding |
70 | | /// |
71 | | /// ```text |
72 | | /// 0 1 2 3 4 5 6 7 |
73 | | /// +---+---+---+---+---+---+---+---+ |
74 | | /// | 0 | 1 | Index (6+) | |
75 | | /// +---+---+-----------------------+ |
76 | | /// | H | Value Length (7+) | |
77 | | /// +---+---------------------------+ |
78 | | /// | Value String (Length octets) | |
79 | | /// +-------------------------------+ |
80 | | /// ``` |
81 | | LiteralWithIndexing, |
82 | | |
83 | | /// Literal Header Field without Indexing |
84 | | /// |
85 | | /// A literal header field without indexing representation results in |
86 | | /// appending a header field to the decoded header list without altering the |
87 | | /// dynamic table. |
88 | | /// |
89 | | /// # Header encoding |
90 | | /// |
91 | | /// ```text |
92 | | /// 0 1 2 3 4 5 6 7 |
93 | | /// +---+---+---+---+---+---+---+---+ |
94 | | /// | 0 | 0 | 0 | 0 | Index (4+) | |
95 | | /// +---+---+-----------------------+ |
96 | | /// | H | Value Length (7+) | |
97 | | /// +---+---------------------------+ |
98 | | /// | Value String (Length octets) | |
99 | | /// +-------------------------------+ |
100 | | /// ``` |
101 | | LiteralWithoutIndexing, |
102 | | |
103 | | /// Literal Header Field Never Indexed |
104 | | /// |
105 | | /// A literal header field never-indexed representation results in appending |
106 | | /// a header field to the decoded header list without altering the dynamic |
107 | | /// table. Intermediaries MUST use the same representation for encoding this |
108 | | /// header field. |
109 | | /// |
110 | | /// ```text |
111 | | /// 0 1 2 3 4 5 6 7 |
112 | | /// +---+---+---+---+---+---+---+---+ |
113 | | /// | 0 | 0 | 0 | 1 | Index (4+) | |
114 | | /// +---+---+-----------------------+ |
115 | | /// | H | Value Length (7+) | |
116 | | /// +---+---------------------------+ |
117 | | /// | Value String (Length octets) | |
118 | | /// +-------------------------------+ |
119 | | /// ``` |
120 | | LiteralNeverIndexed, |
121 | | |
122 | | /// Dynamic Table Size Update |
123 | | /// |
124 | | /// A dynamic table size update signals a change to the size of the dynamic |
125 | | /// table. |
126 | | /// |
127 | | /// # Header encoding |
128 | | /// |
129 | | /// ```text |
130 | | /// 0 1 2 3 4 5 6 7 |
131 | | /// +---+---+---+---+---+---+---+---+ |
132 | | /// | 0 | 0 | 1 | Max size (5+) | |
133 | | /// +---+---------------------------+ |
134 | | /// ``` |
135 | | SizeUpdate, |
136 | | } |
137 | | |
138 | | #[derive(Debug)] |
139 | | struct Table { |
140 | | entries: VecDeque<Header>, |
141 | | size: usize, |
142 | | max_size: usize, |
143 | | } |
144 | | |
145 | | struct StringMarker { |
146 | | offset: usize, |
147 | | len: usize, |
148 | | string: Option<Bytes>, |
149 | | } |
150 | | |
151 | | // ===== impl Decoder ===== |
152 | | |
153 | | impl Decoder { |
154 | | /// Creates a new `Decoder` with all settings set to default values. |
155 | 0 | pub fn new(size: usize) -> Decoder { |
156 | 0 | Decoder { |
157 | 0 | max_size_update: None, |
158 | 0 | last_max_update: size, |
159 | 0 | table: Table::new(size), |
160 | 0 | buffer: BytesMut::with_capacity(4096), |
161 | 0 | } |
162 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::new Unexecuted instantiation: <h2::hpack::decoder::Decoder>::new Unexecuted instantiation: <h2::hpack::decoder::Decoder>::new |
163 | | |
164 | | /// Queues a potential size update |
165 | | #[allow(dead_code)] |
166 | 0 | pub fn queue_size_update(&mut self, size: usize) { |
167 | 0 | let size = match self.max_size_update { |
168 | 0 | Some(v) => cmp::max(v, size), |
169 | 0 | None => size, |
170 | | }; |
171 | | |
172 | 0 | self.max_size_update = Some(size); |
173 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::queue_size_update Unexecuted instantiation: <h2::hpack::decoder::Decoder>::queue_size_update Unexecuted instantiation: <h2::hpack::decoder::Decoder>::queue_size_update |
174 | | |
175 | | /// Decodes the headers found in the given buffer. |
176 | 0 | pub fn decode<F>( |
177 | 0 | &mut self, |
178 | 0 | src: &mut Cursor<&mut BytesMut>, |
179 | 0 | mut f: F, |
180 | 0 | ) -> Result<(), DecoderError> |
181 | 0 | where |
182 | 0 | F: FnMut(Header), |
183 | 0 | { |
184 | | use self::Representation::*; |
185 | | |
186 | 0 | let mut can_resize = true; |
187 | | |
188 | 0 | if let Some(size) = self.max_size_update.take() { |
189 | 0 | self.last_max_update = size; |
190 | 0 | } |
191 | | |
192 | 0 | let span = tracing::trace_span!("hpack::decode"); |
193 | 0 | let _e = span.enter(); |
194 | 0 |
|
195 | 0 | tracing::trace!("decode"); |
196 | | |
197 | 0 | while let Some(ty) = peek_u8(src) { |
198 | | // At this point we are always at the beginning of the next block |
199 | | // within the HPACK data. The type of the block can always be |
200 | | // determined from the first byte. |
201 | 0 | match Representation::load(ty)? { |
202 | | Indexed => { |
203 | 0 | tracing::trace!(rem = src.remaining(), kind = %"Indexed"); |
204 | 0 | can_resize = false; |
205 | 0 | let entry = self.decode_indexed(src)?; |
206 | 0 | consume(src); |
207 | 0 | f(entry); |
208 | | } |
209 | | LiteralWithIndexing => { |
210 | 0 | tracing::trace!(rem = src.remaining(), kind = %"LiteralWithIndexing"); |
211 | 0 | can_resize = false; |
212 | 0 | let entry = self.decode_literal(src, true)?; |
213 | | |
214 | | // Insert the header into the table |
215 | 0 | self.table.insert(entry.clone()); |
216 | 0 | consume(src); |
217 | 0 |
|
218 | 0 | f(entry); |
219 | | } |
220 | | LiteralWithoutIndexing => { |
221 | 0 | tracing::trace!(rem = src.remaining(), kind = %"LiteralWithoutIndexing"); |
222 | 0 | can_resize = false; |
223 | 0 | let entry = self.decode_literal(src, false)?; |
224 | 0 | consume(src); |
225 | 0 | f(entry); |
226 | | } |
227 | | LiteralNeverIndexed => { |
228 | 0 | tracing::trace!(rem = src.remaining(), kind = %"LiteralNeverIndexed"); |
229 | 0 | can_resize = false; |
230 | 0 | let entry = self.decode_literal(src, false)?; |
231 | 0 | consume(src); |
232 | 0 |
|
233 | 0 | // TODO: Track that this should never be indexed |
234 | 0 |
|
235 | 0 | f(entry); |
236 | | } |
237 | | SizeUpdate => { |
238 | 0 | tracing::trace!(rem = src.remaining(), kind = %"SizeUpdate"); |
239 | 0 | if !can_resize { |
240 | 0 | return Err(DecoderError::InvalidMaxDynamicSize); |
241 | 0 | } |
242 | 0 |
|
243 | 0 | // Handle the dynamic table size update |
244 | 0 | self.process_size_update(src)?; |
245 | 0 | consume(src); |
246 | | } |
247 | | } |
248 | | } |
249 | | |
250 | 0 | Ok(()) |
251 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode::<<h2::frame::headers::HeaderBlock>::load::{closure#0}> Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode::<h2::fuzz_bridge::fuzz_logic::fuzz_hpack::{closure#0}> Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode::<<h2::frame::headers::HeaderBlock>::load::{closure#0}> Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode::<h2::fuzz_bridge::fuzz_logic::fuzz_hpack::{closure#0}> Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode::<<h2::frame::headers::HeaderBlock>::load::{closure#0}> Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode::<h2::fuzz_bridge::fuzz_logic::fuzz_hpack::{closure#0}> |
252 | | |
253 | 0 | fn process_size_update(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<(), DecoderError> { |
254 | 0 | let new_size = decode_int(buf, 5)?; |
255 | | |
256 | 0 | if new_size > self.last_max_update { |
257 | 0 | return Err(DecoderError::InvalidMaxDynamicSize); |
258 | 0 | } |
259 | 0 |
|
260 | 0 | tracing::debug!( |
261 | 0 | from = self.table.size(), |
262 | 0 | to = new_size, |
263 | 0 | "Decoder changed max table size" |
264 | | ); |
265 | | |
266 | 0 | self.table.set_max_size(new_size); |
267 | 0 |
|
268 | 0 | Ok(()) |
269 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::process_size_update Unexecuted instantiation: <h2::hpack::decoder::Decoder>::process_size_update Unexecuted instantiation: <h2::hpack::decoder::Decoder>::process_size_update |
270 | | |
271 | 0 | fn decode_indexed(&self, buf: &mut Cursor<&mut BytesMut>) -> Result<Header, DecoderError> { |
272 | 0 | let index = decode_int(buf, 7)?; |
273 | 0 | self.table.get(index) |
274 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_indexed Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_indexed Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_indexed |
275 | | |
276 | 0 | fn decode_literal( |
277 | 0 | &mut self, |
278 | 0 | buf: &mut Cursor<&mut BytesMut>, |
279 | 0 | index: bool, |
280 | 0 | ) -> Result<Header, DecoderError> { |
281 | 0 | let prefix = if index { 6 } else { 4 }; |
282 | | |
283 | | // Extract the table index for the name, or 0 if not indexed |
284 | 0 | let table_idx = decode_int(buf, prefix)?; |
285 | | |
286 | | // First, read the header name |
287 | 0 | if table_idx == 0 { |
288 | 0 | let old_pos = buf.position(); |
289 | 0 | let name_marker = self.try_decode_string(buf)?; |
290 | 0 | let value_marker = self.try_decode_string(buf)?; |
291 | 0 | buf.set_position(old_pos); |
292 | 0 | // Read the name as a literal |
293 | 0 | let name = name_marker.consume(buf); |
294 | 0 | let value = value_marker.consume(buf); |
295 | 0 | Header::new(name, value) |
296 | | } else { |
297 | 0 | let e = self.table.get(table_idx)?; |
298 | 0 | let value = self.decode_string(buf)?; |
299 | | |
300 | 0 | e.name().into_entry(value) |
301 | | } |
302 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_literal Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_literal Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_literal |
303 | | |
304 | 0 | fn try_decode_string( |
305 | 0 | &mut self, |
306 | 0 | buf: &mut Cursor<&mut BytesMut>, |
307 | 0 | ) -> Result<StringMarker, DecoderError> { |
308 | 0 | let old_pos = buf.position(); |
309 | | const HUFF_FLAG: u8 = 0b1000_0000; |
310 | | |
311 | | // The first bit in the first byte contains the huffman encoded flag. |
312 | 0 | let huff = match peek_u8(buf) { |
313 | 0 | Some(hdr) => (hdr & HUFF_FLAG) == HUFF_FLAG, |
314 | 0 | None => return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream)), |
315 | | }; |
316 | | |
317 | | // Decode the string length using 7 bit prefix |
318 | 0 | let len = decode_int(buf, 7)?; |
319 | | |
320 | 0 | if len > buf.remaining() { |
321 | 0 | tracing::trace!(len, remaining = buf.remaining(), "decode_string underflow",); |
322 | 0 | return Err(DecoderError::NeedMore(NeedMore::StringUnderflow)); |
323 | 0 | } |
324 | 0 |
|
325 | 0 | let offset = (buf.position() - old_pos) as usize; |
326 | 0 | if huff { |
327 | 0 | let ret = { |
328 | 0 | let raw = &buf.chunk()[..len]; |
329 | 0 | huffman::decode(raw, &mut self.buffer).map(|buf| StringMarker { |
330 | 0 | offset, |
331 | 0 | len, |
332 | 0 | string: Some(BytesMut::freeze(buf)), |
333 | 0 | }) Unexecuted instantiation: <h2::hpack::decoder::Decoder>::try_decode_string::{closure#0} Unexecuted instantiation: <h2::hpack::decoder::Decoder>::try_decode_string::{closure#0} Unexecuted instantiation: <h2::hpack::decoder::Decoder>::try_decode_string::{closure#0} |
334 | 0 | }; |
335 | 0 |
|
336 | 0 | buf.advance(len); |
337 | 0 | ret |
338 | | } else { |
339 | 0 | buf.advance(len); |
340 | 0 | Ok(StringMarker { |
341 | 0 | offset, |
342 | 0 | len, |
343 | 0 | string: None, |
344 | 0 | }) |
345 | | } |
346 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::try_decode_string Unexecuted instantiation: <h2::hpack::decoder::Decoder>::try_decode_string Unexecuted instantiation: <h2::hpack::decoder::Decoder>::try_decode_string |
347 | | |
348 | 0 | fn decode_string(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<Bytes, DecoderError> { |
349 | 0 | let old_pos = buf.position(); |
350 | 0 | let marker = self.try_decode_string(buf)?; |
351 | 0 | buf.set_position(old_pos); |
352 | 0 | Ok(marker.consume(buf)) |
353 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_string Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_string Unexecuted instantiation: <h2::hpack::decoder::Decoder>::decode_string |
354 | | } |
355 | | |
356 | | impl Default for Decoder { |
357 | 0 | fn default() -> Decoder { |
358 | 0 | Decoder::new(4096) |
359 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Decoder as core::default::Default>::default Unexecuted instantiation: <h2::hpack::decoder::Decoder as core::default::Default>::default Unexecuted instantiation: <h2::hpack::decoder::Decoder as core::default::Default>::default |
360 | | } |
361 | | |
362 | | // ===== impl Representation ===== |
363 | | |
364 | | impl Representation { |
365 | 0 | pub fn load(byte: u8) -> Result<Representation, DecoderError> { |
366 | | const INDEXED: u8 = 0b1000_0000; |
367 | | const LITERAL_WITH_INDEXING: u8 = 0b0100_0000; |
368 | | const LITERAL_WITHOUT_INDEXING: u8 = 0b1111_0000; |
369 | | const LITERAL_NEVER_INDEXED: u8 = 0b0001_0000; |
370 | | const SIZE_UPDATE_MASK: u8 = 0b1110_0000; |
371 | | const SIZE_UPDATE: u8 = 0b0010_0000; |
372 | | |
373 | | // TODO: What did I even write here? |
374 | | |
375 | 0 | if byte & INDEXED == INDEXED { |
376 | 0 | Ok(Representation::Indexed) |
377 | 0 | } else if byte & LITERAL_WITH_INDEXING == LITERAL_WITH_INDEXING { |
378 | 0 | Ok(Representation::LiteralWithIndexing) |
379 | 0 | } else if byte & LITERAL_WITHOUT_INDEXING == 0 { |
380 | 0 | Ok(Representation::LiteralWithoutIndexing) |
381 | 0 | } else if byte & LITERAL_WITHOUT_INDEXING == LITERAL_NEVER_INDEXED { |
382 | 0 | Ok(Representation::LiteralNeverIndexed) |
383 | 0 | } else if byte & SIZE_UPDATE_MASK == SIZE_UPDATE { |
384 | 0 | Ok(Representation::SizeUpdate) |
385 | | } else { |
386 | 0 | Err(DecoderError::InvalidRepresentation) |
387 | | } |
388 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Representation>::load Unexecuted instantiation: <h2::hpack::decoder::Representation>::load Unexecuted instantiation: <h2::hpack::decoder::Representation>::load |
389 | | } |
390 | | |
391 | 0 | fn decode_int<B: Buf>(buf: &mut B, prefix_size: u8) -> Result<usize, DecoderError> { |
392 | | // The octet limit is chosen such that the maximum allowed *value* can |
393 | | // never overflow an unsigned 32-bit integer. The maximum value of any |
394 | | // integer that can be encoded with 5 octets is ~2^28 |
395 | | const MAX_BYTES: usize = 5; |
396 | | const VARINT_MASK: u8 = 0b0111_1111; |
397 | | const VARINT_FLAG: u8 = 0b1000_0000; |
398 | | |
399 | 0 | if prefix_size < 1 || prefix_size > 8 { |
400 | 0 | return Err(DecoderError::InvalidIntegerPrefix); |
401 | 0 | } |
402 | 0 |
|
403 | 0 | if !buf.has_remaining() { |
404 | 0 | return Err(DecoderError::NeedMore(NeedMore::IntegerUnderflow)); |
405 | 0 | } |
406 | | |
407 | 0 | let mask = if prefix_size == 8 { |
408 | 0 | 0xFF |
409 | | } else { |
410 | 0 | (1u8 << prefix_size).wrapping_sub(1) |
411 | | }; |
412 | | |
413 | 0 | let mut ret = (buf.get_u8() & mask) as usize; |
414 | 0 |
|
415 | 0 | if ret < mask as usize { |
416 | | // Value fits in the prefix bits |
417 | 0 | return Ok(ret); |
418 | 0 | } |
419 | 0 |
|
420 | 0 | // The int did not fit in the prefix bits, so continue reading. |
421 | 0 | // |
422 | 0 | // The total number of bytes used to represent the int. The first byte was |
423 | 0 | // the prefix, so start at 1. |
424 | 0 | let mut bytes = 1; |
425 | 0 |
|
426 | 0 | // The rest of the int is stored as a varint -- 7 bits for the value and 1 |
427 | 0 | // bit to indicate if it is the last byte. |
428 | 0 | let mut shift = 0; |
429 | | |
430 | 0 | while buf.has_remaining() { |
431 | 0 | let b = buf.get_u8(); |
432 | 0 |
|
433 | 0 | bytes += 1; |
434 | 0 | ret += ((b & VARINT_MASK) as usize) << shift; |
435 | 0 | shift += 7; |
436 | 0 |
|
437 | 0 | if b & VARINT_FLAG == 0 { |
438 | 0 | return Ok(ret); |
439 | 0 | } |
440 | 0 |
|
441 | 0 | if bytes == MAX_BYTES { |
442 | | // The spec requires that this situation is an error |
443 | 0 | return Err(DecoderError::IntegerOverflow); |
444 | 0 | } |
445 | | } |
446 | | |
447 | 0 | Err(DecoderError::NeedMore(NeedMore::IntegerUnderflow)) |
448 | 0 | } Unexecuted instantiation: h2::hpack::decoder::decode_int::<std::io::cursor::Cursor<&mut bytes::bytes_mut::BytesMut>> Unexecuted instantiation: h2::hpack::decoder::decode_int::<std::io::cursor::Cursor<&mut bytes::bytes_mut::BytesMut>> Unexecuted instantiation: h2::hpack::decoder::decode_int::<std::io::cursor::Cursor<&mut bytes::bytes_mut::BytesMut>> |
449 | | |
450 | 0 | fn peek_u8<B: Buf>(buf: &B) -> Option<u8> { |
451 | 0 | if buf.has_remaining() { |
452 | 0 | Some(buf.chunk()[0]) |
453 | | } else { |
454 | 0 | None |
455 | | } |
456 | 0 | } Unexecuted instantiation: h2::hpack::decoder::peek_u8::<std::io::cursor::Cursor<&mut bytes::bytes_mut::BytesMut>> Unexecuted instantiation: h2::hpack::decoder::peek_u8::<std::io::cursor::Cursor<&mut bytes::bytes_mut::BytesMut>> Unexecuted instantiation: h2::hpack::decoder::peek_u8::<std::io::cursor::Cursor<&mut bytes::bytes_mut::BytesMut>> |
457 | | |
458 | 0 | fn take(buf: &mut Cursor<&mut BytesMut>, n: usize) -> Bytes { |
459 | 0 | let pos = buf.position() as usize; |
460 | 0 | let mut head = buf.get_mut().split_to(pos + n); |
461 | 0 | buf.set_position(0); |
462 | 0 | head.advance(pos); |
463 | 0 | head.freeze() |
464 | 0 | } Unexecuted instantiation: h2::hpack::decoder::take Unexecuted instantiation: h2::hpack::decoder::take Unexecuted instantiation: h2::hpack::decoder::take |
465 | | |
466 | | impl StringMarker { |
467 | 0 | fn consume(self, buf: &mut Cursor<&mut BytesMut>) -> Bytes { |
468 | 0 | buf.advance(self.offset); |
469 | 0 | match self.string { |
470 | 0 | Some(string) => { |
471 | 0 | buf.advance(self.len); |
472 | 0 | string |
473 | | } |
474 | 0 | None => take(buf, self.len), |
475 | | } |
476 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::StringMarker>::consume Unexecuted instantiation: <h2::hpack::decoder::StringMarker>::consume Unexecuted instantiation: <h2::hpack::decoder::StringMarker>::consume |
477 | | } |
478 | | |
479 | 0 | fn consume(buf: &mut Cursor<&mut BytesMut>) { |
480 | 0 | // remove bytes from the internal BytesMut when they have been successfully |
481 | 0 | // decoded. This is a more permanent cursor position, which will be |
482 | 0 | // used to resume if decoding was only partial. |
483 | 0 | take(buf, 0); |
484 | 0 | } Unexecuted instantiation: h2::hpack::decoder::consume Unexecuted instantiation: h2::hpack::decoder::consume Unexecuted instantiation: h2::hpack::decoder::consume |
485 | | |
486 | | // ===== impl Table ===== |
487 | | |
488 | | impl Table { |
489 | 0 | fn new(max_size: usize) -> Table { |
490 | 0 | Table { |
491 | 0 | entries: VecDeque::new(), |
492 | 0 | size: 0, |
493 | 0 | max_size, |
494 | 0 | } |
495 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::new Unexecuted instantiation: <h2::hpack::decoder::Table>::new Unexecuted instantiation: <h2::hpack::decoder::Table>::new |
496 | | |
497 | 0 | fn size(&self) -> usize { |
498 | 0 | self.size |
499 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::size Unexecuted instantiation: <h2::hpack::decoder::Table>::size Unexecuted instantiation: <h2::hpack::decoder::Table>::size |
500 | | |
501 | | /// Returns the entry located at the given index. |
502 | | /// |
503 | | /// The table is 1-indexed and constructed in such a way that the first |
504 | | /// entries belong to the static table, followed by entries in the dynamic |
505 | | /// table. They are merged into a single index address space, though. |
506 | | /// |
507 | | /// This is according to the [HPACK spec, section 2.3.3.] |
508 | | /// (http://http2.github.io/http2-spec/compression.html#index.address.space) |
509 | 0 | pub fn get(&self, index: usize) -> Result<Header, DecoderError> { |
510 | 0 | if index == 0 { |
511 | 0 | return Err(DecoderError::InvalidTableIndex); |
512 | 0 | } |
513 | 0 |
|
514 | 0 | if index <= 61 { |
515 | 0 | return Ok(get_static(index)); |
516 | 0 | } |
517 | 0 |
|
518 | 0 | // Convert the index for lookup in the entries structure. |
519 | 0 | match self.entries.get(index - 62) { |
520 | 0 | Some(e) => Ok(e.clone()), |
521 | 0 | None => Err(DecoderError::InvalidTableIndex), |
522 | | } |
523 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::get Unexecuted instantiation: <h2::hpack::decoder::Table>::get Unexecuted instantiation: <h2::hpack::decoder::Table>::get |
524 | | |
525 | 0 | fn insert(&mut self, entry: Header) { |
526 | 0 | let len = entry.len(); |
527 | 0 |
|
528 | 0 | self.reserve(len); |
529 | 0 |
|
530 | 0 | if self.size + len <= self.max_size { |
531 | 0 | self.size += len; |
532 | 0 |
|
533 | 0 | // Track the entry |
534 | 0 | self.entries.push_front(entry); |
535 | 0 | } |
536 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::insert Unexecuted instantiation: <h2::hpack::decoder::Table>::insert Unexecuted instantiation: <h2::hpack::decoder::Table>::insert |
537 | | |
538 | 0 | fn set_max_size(&mut self, size: usize) { |
539 | 0 | self.max_size = size; |
540 | 0 | // Make the table size fit within the new constraints. |
541 | 0 | self.consolidate(); |
542 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::set_max_size Unexecuted instantiation: <h2::hpack::decoder::Table>::set_max_size Unexecuted instantiation: <h2::hpack::decoder::Table>::set_max_size |
543 | | |
544 | 0 | fn reserve(&mut self, size: usize) { |
545 | 0 | while self.size + size > self.max_size { |
546 | 0 | match self.entries.pop_back() { |
547 | 0 | Some(last) => { |
548 | 0 | self.size -= last.len(); |
549 | 0 | } |
550 | 0 | None => return, |
551 | | } |
552 | | } |
553 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::reserve Unexecuted instantiation: <h2::hpack::decoder::Table>::reserve Unexecuted instantiation: <h2::hpack::decoder::Table>::reserve |
554 | | |
555 | 0 | fn consolidate(&mut self) { |
556 | 0 | while self.size > self.max_size { |
557 | | { |
558 | 0 | let last = match self.entries.back() { |
559 | 0 | Some(x) => x, |
560 | | None => { |
561 | | // Can never happen as the size of the table must reach |
562 | | // 0 by the time we've exhausted all elements. |
563 | 0 | panic!("Size of table != 0, but no headers left!"); |
564 | | } |
565 | | }; |
566 | | |
567 | 0 | self.size -= last.len(); |
568 | 0 | } |
569 | 0 |
|
570 | 0 | self.entries.pop_back(); |
571 | | } |
572 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::Table>::consolidate Unexecuted instantiation: <h2::hpack::decoder::Table>::consolidate Unexecuted instantiation: <h2::hpack::decoder::Table>::consolidate |
573 | | } |
574 | | |
575 | | // ===== impl DecoderError ===== |
576 | | |
577 | | impl From<Utf8Error> for DecoderError { |
578 | 0 | fn from(_: Utf8Error) -> DecoderError { |
579 | 0 | // TODO: Better error? |
580 | 0 | DecoderError::InvalidUtf8 |
581 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<core::str::error::Utf8Error>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<core::str::error::Utf8Error>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<core::str::error::Utf8Error>>::from |
582 | | } |
583 | | |
584 | | impl From<header::InvalidHeaderValue> for DecoderError { |
585 | 0 | fn from(_: header::InvalidHeaderValue) -> DecoderError { |
586 | 0 | // TODO: Better error? |
587 | 0 | DecoderError::InvalidUtf8 |
588 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::header::value::InvalidHeaderValue>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::header::value::InvalidHeaderValue>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::header::value::InvalidHeaderValue>>::from |
589 | | } |
590 | | |
591 | | impl From<header::InvalidHeaderName> for DecoderError { |
592 | 0 | fn from(_: header::InvalidHeaderName) -> DecoderError { |
593 | 0 | // TODO: Better error |
594 | 0 | DecoderError::InvalidUtf8 |
595 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::header::name::InvalidHeaderName>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::header::name::InvalidHeaderName>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::header::name::InvalidHeaderName>>::from |
596 | | } |
597 | | |
598 | | impl From<method::InvalidMethod> for DecoderError { |
599 | 0 | fn from(_: method::InvalidMethod) -> DecoderError { |
600 | 0 | // TODO: Better error |
601 | 0 | DecoderError::InvalidUtf8 |
602 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::method::InvalidMethod>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::method::InvalidMethod>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::method::InvalidMethod>>::from |
603 | | } |
604 | | |
605 | | impl From<status::InvalidStatusCode> for DecoderError { |
606 | 0 | fn from(_: status::InvalidStatusCode) -> DecoderError { |
607 | 0 | // TODO: Better error |
608 | 0 | DecoderError::InvalidUtf8 |
609 | 0 | } Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::status::InvalidStatusCode>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::status::InvalidStatusCode>>::from Unexecuted instantiation: <h2::hpack::decoder::DecoderError as core::convert::From<http::status::InvalidStatusCode>>::from |
610 | | } |
611 | | |
612 | | impl From<DecoderError> for frame::Error { |
613 | 0 | fn from(src: DecoderError) -> Self { |
614 | 0 | frame::Error::Hpack(src) |
615 | 0 | } Unexecuted instantiation: <h2::frame::Error as core::convert::From<h2::hpack::decoder::DecoderError>>::from Unexecuted instantiation: <h2::frame::Error as core::convert::From<h2::hpack::decoder::DecoderError>>::from Unexecuted instantiation: <h2::frame::Error as core::convert::From<h2::hpack::decoder::DecoderError>>::from |
616 | | } |
617 | | |
618 | | /// Get an entry from the static table |
619 | 0 | pub fn get_static(idx: usize) -> Header { |
620 | | use http::header::HeaderValue; |
621 | | |
622 | 0 | match idx { |
623 | 0 | 1 => Header::Authority(BytesStr::from_static("")), |
624 | 0 | 2 => Header::Method(Method::GET), |
625 | 0 | 3 => Header::Method(Method::POST), |
626 | 0 | 4 => Header::Path(BytesStr::from_static("/")), |
627 | 0 | 5 => Header::Path(BytesStr::from_static("/index.html")), |
628 | 0 | 6 => Header::Scheme(BytesStr::from_static("http")), |
629 | 0 | 7 => Header::Scheme(BytesStr::from_static("https")), |
630 | 0 | 8 => Header::Status(StatusCode::OK), |
631 | 0 | 9 => Header::Status(StatusCode::NO_CONTENT), |
632 | 0 | 10 => Header::Status(StatusCode::PARTIAL_CONTENT), |
633 | 0 | 11 => Header::Status(StatusCode::NOT_MODIFIED), |
634 | 0 | 12 => Header::Status(StatusCode::BAD_REQUEST), |
635 | 0 | 13 => Header::Status(StatusCode::NOT_FOUND), |
636 | 0 | 14 => Header::Status(StatusCode::INTERNAL_SERVER_ERROR), |
637 | 0 | 15 => Header::Field { |
638 | 0 | name: header::ACCEPT_CHARSET, |
639 | 0 | value: HeaderValue::from_static(""), |
640 | 0 | }, |
641 | 0 | 16 => Header::Field { |
642 | 0 | name: header::ACCEPT_ENCODING, |
643 | 0 | value: HeaderValue::from_static("gzip, deflate"), |
644 | 0 | }, |
645 | 0 | 17 => Header::Field { |
646 | 0 | name: header::ACCEPT_LANGUAGE, |
647 | 0 | value: HeaderValue::from_static(""), |
648 | 0 | }, |
649 | 0 | 18 => Header::Field { |
650 | 0 | name: header::ACCEPT_RANGES, |
651 | 0 | value: HeaderValue::from_static(""), |
652 | 0 | }, |
653 | 0 | 19 => Header::Field { |
654 | 0 | name: header::ACCEPT, |
655 | 0 | value: HeaderValue::from_static(""), |
656 | 0 | }, |
657 | 0 | 20 => Header::Field { |
658 | 0 | name: header::ACCESS_CONTROL_ALLOW_ORIGIN, |
659 | 0 | value: HeaderValue::from_static(""), |
660 | 0 | }, |
661 | 0 | 21 => Header::Field { |
662 | 0 | name: header::AGE, |
663 | 0 | value: HeaderValue::from_static(""), |
664 | 0 | }, |
665 | 0 | 22 => Header::Field { |
666 | 0 | name: header::ALLOW, |
667 | 0 | value: HeaderValue::from_static(""), |
668 | 0 | }, |
669 | 0 | 23 => Header::Field { |
670 | 0 | name: header::AUTHORIZATION, |
671 | 0 | value: HeaderValue::from_static(""), |
672 | 0 | }, |
673 | 0 | 24 => Header::Field { |
674 | 0 | name: header::CACHE_CONTROL, |
675 | 0 | value: HeaderValue::from_static(""), |
676 | 0 | }, |
677 | 0 | 25 => Header::Field { |
678 | 0 | name: header::CONTENT_DISPOSITION, |
679 | 0 | value: HeaderValue::from_static(""), |
680 | 0 | }, |
681 | 0 | 26 => Header::Field { |
682 | 0 | name: header::CONTENT_ENCODING, |
683 | 0 | value: HeaderValue::from_static(""), |
684 | 0 | }, |
685 | 0 | 27 => Header::Field { |
686 | 0 | name: header::CONTENT_LANGUAGE, |
687 | 0 | value: HeaderValue::from_static(""), |
688 | 0 | }, |
689 | 0 | 28 => Header::Field { |
690 | 0 | name: header::CONTENT_LENGTH, |
691 | 0 | value: HeaderValue::from_static(""), |
692 | 0 | }, |
693 | 0 | 29 => Header::Field { |
694 | 0 | name: header::CONTENT_LOCATION, |
695 | 0 | value: HeaderValue::from_static(""), |
696 | 0 | }, |
697 | 0 | 30 => Header::Field { |
698 | 0 | name: header::CONTENT_RANGE, |
699 | 0 | value: HeaderValue::from_static(""), |
700 | 0 | }, |
701 | 0 | 31 => Header::Field { |
702 | 0 | name: header::CONTENT_TYPE, |
703 | 0 | value: HeaderValue::from_static(""), |
704 | 0 | }, |
705 | 0 | 32 => Header::Field { |
706 | 0 | name: header::COOKIE, |
707 | 0 | value: HeaderValue::from_static(""), |
708 | 0 | }, |
709 | 0 | 33 => Header::Field { |
710 | 0 | name: header::DATE, |
711 | 0 | value: HeaderValue::from_static(""), |
712 | 0 | }, |
713 | 0 | 34 => Header::Field { |
714 | 0 | name: header::ETAG, |
715 | 0 | value: HeaderValue::from_static(""), |
716 | 0 | }, |
717 | 0 | 35 => Header::Field { |
718 | 0 | name: header::EXPECT, |
719 | 0 | value: HeaderValue::from_static(""), |
720 | 0 | }, |
721 | 0 | 36 => Header::Field { |
722 | 0 | name: header::EXPIRES, |
723 | 0 | value: HeaderValue::from_static(""), |
724 | 0 | }, |
725 | 0 | 37 => Header::Field { |
726 | 0 | name: header::FROM, |
727 | 0 | value: HeaderValue::from_static(""), |
728 | 0 | }, |
729 | 0 | 38 => Header::Field { |
730 | 0 | name: header::HOST, |
731 | 0 | value: HeaderValue::from_static(""), |
732 | 0 | }, |
733 | 0 | 39 => Header::Field { |
734 | 0 | name: header::IF_MATCH, |
735 | 0 | value: HeaderValue::from_static(""), |
736 | 0 | }, |
737 | 0 | 40 => Header::Field { |
738 | 0 | name: header::IF_MODIFIED_SINCE, |
739 | 0 | value: HeaderValue::from_static(""), |
740 | 0 | }, |
741 | 0 | 41 => Header::Field { |
742 | 0 | name: header::IF_NONE_MATCH, |
743 | 0 | value: HeaderValue::from_static(""), |
744 | 0 | }, |
745 | 0 | 42 => Header::Field { |
746 | 0 | name: header::IF_RANGE, |
747 | 0 | value: HeaderValue::from_static(""), |
748 | 0 | }, |
749 | 0 | 43 => Header::Field { |
750 | 0 | name: header::IF_UNMODIFIED_SINCE, |
751 | 0 | value: HeaderValue::from_static(""), |
752 | 0 | }, |
753 | 0 | 44 => Header::Field { |
754 | 0 | name: header::LAST_MODIFIED, |
755 | 0 | value: HeaderValue::from_static(""), |
756 | 0 | }, |
757 | 0 | 45 => Header::Field { |
758 | 0 | name: header::LINK, |
759 | 0 | value: HeaderValue::from_static(""), |
760 | 0 | }, |
761 | 0 | 46 => Header::Field { |
762 | 0 | name: header::LOCATION, |
763 | 0 | value: HeaderValue::from_static(""), |
764 | 0 | }, |
765 | 0 | 47 => Header::Field { |
766 | 0 | name: header::MAX_FORWARDS, |
767 | 0 | value: HeaderValue::from_static(""), |
768 | 0 | }, |
769 | 0 | 48 => Header::Field { |
770 | 0 | name: header::PROXY_AUTHENTICATE, |
771 | 0 | value: HeaderValue::from_static(""), |
772 | 0 | }, |
773 | 0 | 49 => Header::Field { |
774 | 0 | name: header::PROXY_AUTHORIZATION, |
775 | 0 | value: HeaderValue::from_static(""), |
776 | 0 | }, |
777 | 0 | 50 => Header::Field { |
778 | 0 | name: header::RANGE, |
779 | 0 | value: HeaderValue::from_static(""), |
780 | 0 | }, |
781 | 0 | 51 => Header::Field { |
782 | 0 | name: header::REFERER, |
783 | 0 | value: HeaderValue::from_static(""), |
784 | 0 | }, |
785 | 0 | 52 => Header::Field { |
786 | 0 | name: header::REFRESH, |
787 | 0 | value: HeaderValue::from_static(""), |
788 | 0 | }, |
789 | 0 | 53 => Header::Field { |
790 | 0 | name: header::RETRY_AFTER, |
791 | 0 | value: HeaderValue::from_static(""), |
792 | 0 | }, |
793 | 0 | 54 => Header::Field { |
794 | 0 | name: header::SERVER, |
795 | 0 | value: HeaderValue::from_static(""), |
796 | 0 | }, |
797 | 0 | 55 => Header::Field { |
798 | 0 | name: header::SET_COOKIE, |
799 | 0 | value: HeaderValue::from_static(""), |
800 | 0 | }, |
801 | 0 | 56 => Header::Field { |
802 | 0 | name: header::STRICT_TRANSPORT_SECURITY, |
803 | 0 | value: HeaderValue::from_static(""), |
804 | 0 | }, |
805 | 0 | 57 => Header::Field { |
806 | 0 | name: header::TRANSFER_ENCODING, |
807 | 0 | value: HeaderValue::from_static(""), |
808 | 0 | }, |
809 | 0 | 58 => Header::Field { |
810 | 0 | name: header::USER_AGENT, |
811 | 0 | value: HeaderValue::from_static(""), |
812 | 0 | }, |
813 | 0 | 59 => Header::Field { |
814 | 0 | name: header::VARY, |
815 | 0 | value: HeaderValue::from_static(""), |
816 | 0 | }, |
817 | 0 | 60 => Header::Field { |
818 | 0 | name: header::VIA, |
819 | 0 | value: HeaderValue::from_static(""), |
820 | 0 | }, |
821 | 0 | 61 => Header::Field { |
822 | 0 | name: header::WWW_AUTHENTICATE, |
823 | 0 | value: HeaderValue::from_static(""), |
824 | 0 | }, |
825 | 0 | _ => unreachable!(), |
826 | | } |
827 | 0 | } Unexecuted instantiation: h2::hpack::decoder::get_static Unexecuted instantiation: h2::hpack::decoder::get_static Unexecuted instantiation: h2::hpack::decoder::get_static |
828 | | |
829 | | #[cfg(test)] |
830 | | mod test { |
831 | | use super::*; |
832 | | |
833 | | #[test] |
834 | | fn test_peek_u8() { |
835 | | let b = 0xff; |
836 | | let mut buf = Cursor::new(vec![b]); |
837 | | assert_eq!(peek_u8(&buf), Some(b)); |
838 | | assert_eq!(buf.get_u8(), b); |
839 | | assert_eq!(peek_u8(&buf), None); |
840 | | } |
841 | | |
842 | | #[test] |
843 | | fn test_decode_string_empty() { |
844 | | let mut de = Decoder::new(0); |
845 | | let mut buf = BytesMut::new(); |
846 | | let err = de.decode_string(&mut Cursor::new(&mut buf)).unwrap_err(); |
847 | | assert_eq!(err, DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream)); |
848 | | } |
849 | | |
850 | | #[test] |
851 | | fn test_decode_empty() { |
852 | | let mut de = Decoder::new(0); |
853 | | let mut buf = BytesMut::new(); |
854 | | let _: () = de.decode(&mut Cursor::new(&mut buf), |_| {}).unwrap(); |
855 | | } |
856 | | |
857 | | #[test] |
858 | | fn test_decode_indexed_larger_than_table() { |
859 | | let mut de = Decoder::new(0); |
860 | | |
861 | | let mut buf = BytesMut::new(); |
862 | | buf.extend([0b01000000, 0x80 | 2]); |
863 | | buf.extend(huff_encode(b"foo")); |
864 | | buf.extend([0x80 | 3]); |
865 | | buf.extend(huff_encode(b"bar")); |
866 | | |
867 | | let mut res = vec![]; |
868 | | de.decode(&mut Cursor::new(&mut buf), |h| { |
869 | | res.push(h); |
870 | | }) |
871 | | .unwrap(); |
872 | | |
873 | | assert_eq!(res.len(), 1); |
874 | | assert_eq!(de.table.size(), 0); |
875 | | |
876 | | match res[0] { |
877 | | Header::Field { |
878 | | ref name, |
879 | | ref value, |
880 | | } => { |
881 | | assert_eq!(name, "foo"); |
882 | | assert_eq!(value, "bar"); |
883 | | } |
884 | | _ => panic!(), |
885 | | } |
886 | | } |
887 | | |
888 | | fn huff_encode(src: &[u8]) -> BytesMut { |
889 | | let mut buf = BytesMut::new(); |
890 | | huffman::encode(src, &mut buf); |
891 | | buf |
892 | | } |
893 | | |
894 | | #[test] |
895 | | fn test_decode_continuation_header_with_non_huff_encoded_name() { |
896 | | let mut de = Decoder::new(0); |
897 | | let value = huff_encode(b"bar"); |
898 | | let mut buf = BytesMut::new(); |
899 | | // header name is non_huff encoded |
900 | | buf.extend([0b01000000, 3]); |
901 | | buf.extend(b"foo"); |
902 | | // header value is partial |
903 | | buf.extend([0x80 | 3]); |
904 | | buf.extend(&value[0..1]); |
905 | | |
906 | | let mut res = vec![]; |
907 | | let e = de |
908 | | .decode(&mut Cursor::new(&mut buf), |h| { |
909 | | res.push(h); |
910 | | }) |
911 | | .unwrap_err(); |
912 | | // decode error because the header value is partial |
913 | | assert_eq!(e, DecoderError::NeedMore(NeedMore::StringUnderflow)); |
914 | | |
915 | | // extend buf with the remaining header value |
916 | | buf.extend(&value[1..]); |
917 | | de.decode(&mut Cursor::new(&mut buf), |h| { |
918 | | res.push(h); |
919 | | }) |
920 | | .unwrap(); |
921 | | |
922 | | assert_eq!(res.len(), 1); |
923 | | assert_eq!(de.table.size(), 0); |
924 | | |
925 | | match res[0] { |
926 | | Header::Field { |
927 | | ref name, |
928 | | ref value, |
929 | | } => { |
930 | | assert_eq!(name, "foo"); |
931 | | assert_eq!(value, "bar"); |
932 | | } |
933 | | _ => panic!(), |
934 | | } |
935 | | } |
936 | | } |