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