Skip to main content

h2/hpack/
encoder.rs

1use super::table::{Index, Table};
2use super::{huffman, Header};
3
4use bytes::{BufMut, BytesMut};
5use http::header::{HeaderName, HeaderValue};
6
7const DEFAULT_MAX_ALLOWED_SIZE: usize = 4 * 1024;
8
9#[derive(Debug)]
10pub struct Encoder {
11    table: Table,
12    max_allowed_size: usize,
13    size_update: Option<SizeUpdate>,
14    /// Reusable buffer for the encoded header block of a single frame.
15    ///
16    /// A header block only has to live until it is copied into the
17    /// connection write buffer, so the buffer that holds it can be reused
18    /// across frames instead of being allocated and freed per frame. See
19    /// `take_scratch` / `return_scratch`.
20    scratch: BytesMut,
21}
22
23#[derive(Debug, Copy, Clone, Eq, PartialEq)]
24enum SizeUpdate {
25    One(usize),
26    Two(usize, usize), // min, max
27}
28
29impl Encoder {
30    pub fn new(max_size: usize, capacity: usize) -> Encoder {
31        let max_size = max_size.min(DEFAULT_MAX_ALLOWED_SIZE);
32
33        Encoder {
34            table: Table::new(max_size, capacity),
35            max_allowed_size: DEFAULT_MAX_ALLOWED_SIZE,
36            size_update: None,
37            scratch: BytesMut::new(),
38        }
39    }
40
41    #[cfg(test)]
42    fn set_max_allowed_size(&mut self, max: usize) {
43        self.max_allowed_size = max;
44
45        if self.table.max_size() > max {
46            self.update_max_size(max);
47        }
48    }
49
50    /// Takes the reusable buffer for one header-block encode.
51    ///
52    /// The buffer is returned by `return_scratch` once the encoded block has
53    /// been copied into the write buffer. If it is not returned - the
54    /// CONTINUATION path keeps it, since the remainder is still needed - the
55    /// next call simply starts from a fresh buffer.
56    pub(crate) fn take_scratch(&mut self) -> BytesMut {
57        std::mem::take(&mut self.scratch)
58    }
59
60    /// Returns a fully-written header block buffer for reuse.
61    pub(crate) fn return_scratch(&mut self, scratch: BytesMut) {
62        self.scratch = scratch;
63    }
64
65    /// Queues a max size update.
66    ///
67    /// The next call to `encode` will include a dynamic size update frame.
68    pub fn update_max_size(&mut self, val: usize) {
69        let val = val.min(self.max_allowed_size);
70
71        match self.size_update {
72            Some(SizeUpdate::One(old)) => {
73                if val > old {
74                    if old > self.table.max_size() {
75                        self.size_update = Some(SizeUpdate::One(val));
76                    } else {
77                        self.size_update = Some(SizeUpdate::Two(old, val));
78                    }
79                } else {
80                    self.size_update = Some(SizeUpdate::One(val));
81                }
82            }
83            Some(SizeUpdate::Two(min, _)) => {
84                if val < min {
85                    self.size_update = Some(SizeUpdate::One(val));
86                } else {
87                    self.size_update = Some(SizeUpdate::Two(min, val));
88                }
89            }
90            None => {
91                if val != self.table.max_size() {
92                    // Don't bother writing a frame if the value already matches
93                    // the table's max size.
94                    self.size_update = Some(SizeUpdate::One(val));
95                }
96            }
97        }
98    }
99
100    /// Encode a set of headers into the provide buffer
101    pub fn encode<I>(&mut self, headers: I, dst: &mut BytesMut)
102    where
103        I: IntoIterator<Item = Header<Option<HeaderName>>>,
104    {
105        let span = tracing::trace_span!("hpack::encode");
106        let _e = span.enter();
107
108        self.encode_size_updates(dst);
109
110        let mut last_index = None;
111
112        for header in headers {
113            match header.reify() {
114                // The header has an associated name. In which case, try to
115                // index it in the table.
116                Ok(header) => {
117                    let index = self.table.index(header);
118                    self.encode_header(&index, dst);
119
120                    last_index = Some(index);
121                }
122                // The header does not have an associated name. This means that
123                // the name is the same as the previously yielded header. In
124                // which case, we skip table lookup and just use the same index
125                // as the previous entry.
126                Err(value) => {
127                    self.encode_header_without_name(
128                        last_index.as_ref().unwrap_or_else(|| {
129                            panic!("encoding header without name, but no previous index to use for name");
130                        }),
131                        &value,
132                        dst,
133                    );
134                }
135            }
136        }
137    }
138
139    fn encode_size_updates(&mut self, dst: &mut BytesMut) {
140        match self.size_update.take() {
141            Some(SizeUpdate::One(val)) => {
142                self.table.resize(val);
143                encode_size_update(val, dst);
144            }
145            Some(SizeUpdate::Two(min, max)) => {
146                self.table.resize(min);
147                self.table.resize(max);
148                encode_size_update(min, dst);
149                encode_size_update(max, dst);
150            }
151            None => {}
152        }
153    }
154
155    fn encode_header(&mut self, index: &Index, dst: &mut BytesMut) {
156        match *index {
157            Index::Indexed(idx, _) => {
158                encode_int(idx, 7, 0x80, dst);
159            }
160            Index::Name(idx, _) => {
161                let header = self.table.resolve(index);
162
163                encode_not_indexed(idx, header.value_slice(), header.is_sensitive(), dst);
164            }
165            Index::Inserted(_) => {
166                let header = self.table.resolve(index);
167
168                assert!(!header.is_sensitive());
169
170                dst.put_u8(0b0100_0000);
171
172                encode_str(header.name().as_slice(), dst);
173                encode_str(header.value_slice(), dst);
174            }
175            Index::InsertedValue(idx, _) => {
176                let header = self.table.resolve(index);
177
178                assert!(!header.is_sensitive());
179
180                encode_int(idx, 6, 0b0100_0000, dst);
181                encode_str(header.value_slice(), dst);
182            }
183            Index::NotIndexed(_) => {
184                let header = self.table.resolve(index);
185
186                encode_not_indexed2(
187                    header.name().as_slice(),
188                    header.value_slice(),
189                    header.is_sensitive(),
190                    dst,
191                );
192            }
193        }
194    }
195
196    fn encode_header_without_name(
197        &mut self,
198        last: &Index,
199        value: &HeaderValue,
200        dst: &mut BytesMut,
201    ) {
202        match *last {
203            Index::Indexed(..)
204            | Index::Name(..)
205            | Index::Inserted(..)
206            | Index::InsertedValue(..) => {
207                let idx = self.table.resolve_idx(last);
208
209                encode_not_indexed(idx, value.as_ref(), value.is_sensitive(), dst);
210            }
211            Index::NotIndexed(_) => {
212                let last = self.table.resolve(last);
213
214                encode_not_indexed2(
215                    last.name().as_slice(),
216                    value.as_ref(),
217                    value.is_sensitive(),
218                    dst,
219                );
220            }
221        }
222    }
223}
224
225impl Default for Encoder {
226    fn default() -> Encoder {
227        Encoder::new(4096, 0)
228    }
229}
230
231fn encode_size_update(val: usize, dst: &mut BytesMut) {
232    encode_int(val, 5, 0b0010_0000, dst)
233}
234
235fn encode_not_indexed(name: usize, value: &[u8], sensitive: bool, dst: &mut BytesMut) {
236    if sensitive {
237        encode_int(name, 4, 0b10000, dst);
238    } else {
239        encode_int(name, 4, 0, dst);
240    }
241
242    encode_str(value, dst);
243}
244
245fn encode_not_indexed2(name: &[u8], value: &[u8], sensitive: bool, dst: &mut BytesMut) {
246    if sensitive {
247        dst.put_u8(0b10000);
248    } else {
249        dst.put_u8(0);
250    }
251
252    encode_str(name, dst);
253    encode_str(value, dst);
254}
255
256fn encode_str(val: &[u8], dst: &mut BytesMut) {
257    if !val.is_empty() {
258        let idx = position(dst);
259
260        // Push a placeholder byte for the length header
261        dst.put_u8(0);
262
263        // Encode with huffman
264        huffman::encode(val, dst);
265
266        let huff_len = position(dst) - (idx + 1);
267
268        if encode_int_one_byte(huff_len, 7) {
269            // Write the string head
270            dst[idx] = 0x80 | huff_len as u8;
271        } else {
272            // Write the head to a placeholder
273            const PLACEHOLDER_LEN: usize = 8;
274            let mut buf = [0u8; PLACEHOLDER_LEN];
275
276            let head_len = {
277                let mut head_dst = &mut buf[..];
278                encode_int(huff_len, 7, 0x80, &mut head_dst);
279                PLACEHOLDER_LEN - head_dst.remaining_mut()
280            };
281
282            // This is just done to reserve space in the destination
283            dst.put_slice(&buf[1..head_len]);
284
285            // Shift the header forward
286            for i in 0..huff_len {
287                let src_i = idx + 1 + (huff_len - (i + 1));
288                let dst_i = idx + head_len + (huff_len - (i + 1));
289                dst[dst_i] = dst[src_i];
290            }
291
292            // Copy in the head
293            for i in 0..head_len {
294                dst[idx + i] = buf[i];
295            }
296        }
297    } else {
298        // Write an empty string
299        dst.put_u8(0);
300    }
301}
302
303/// Encode an integer into the given destination buffer
304fn encode_int<B: BufMut>(
305    mut value: usize,   // The integer to encode
306    prefix_bits: usize, // The number of bits in the prefix
307    first_byte: u8,     // The base upon which to start encoding the int
308    dst: &mut B,
309) {
310    if encode_int_one_byte(value, prefix_bits) {
311        dst.put_u8(first_byte | value as u8);
312        return;
313    }
314
315    let low = (1 << prefix_bits) - 1;
316
317    value -= low;
318
319    dst.put_u8(first_byte | low as u8);
320
321    while value >= 128 {
322        dst.put_u8(0b1000_0000 | value as u8);
323
324        value >>= 7;
325    }
326
327    dst.put_u8(value as u8);
328}
329
330/// Returns true if the in the int can be fully encoded in the first byte.
331fn encode_int_one_byte(value: usize, prefix_bits: usize) -> bool {
332    value < (1 << prefix_bits) - 1
333}
334
335fn position(buf: &BytesMut) -> usize {
336    buf.len()
337}
338
339#[cfg(test)]
340mod test {
341    use super::*;
342    use http::*;
343
344    #[test]
345    fn test_encode_method_get() {
346        let mut encoder = Encoder::default();
347        let res = encode(&mut encoder, vec![method("GET")]);
348        assert_eq!(*res, [0x80 | 2]);
349        assert_eq!(encoder.table.len(), 0);
350    }
351
352    #[test]
353    fn test_encode_method_post() {
354        let mut encoder = Encoder::default();
355        let res = encode(&mut encoder, vec![method("POST")]);
356        assert_eq!(*res, [0x80 | 3]);
357        assert_eq!(encoder.table.len(), 0);
358    }
359
360    #[test]
361    fn test_encode_method_patch() {
362        let mut encoder = Encoder::default();
363        let res = encode(&mut encoder, vec![method("PATCH")]);
364
365        assert_eq!(res[0], 0b01000000 | 2); // Incremental indexing w/ name pulled from table
366        assert_eq!(res[1], 0x80 | 5); // header value w/ huffman coding
367
368        assert_eq!("PATCH", huff_decode(&res[2..7]));
369        assert_eq!(encoder.table.len(), 1);
370
371        let res = encode(&mut encoder, vec![method("PATCH")]);
372
373        assert_eq!(1 << 7 | 62, res[0]);
374        assert_eq!(1, res.len());
375    }
376
377    #[test]
378    fn test_encode_indexed_name_literal_value() {
379        let mut encoder = Encoder::default();
380        let res = encode(&mut encoder, vec![header("content-language", "foo")]);
381
382        assert_eq!(res[0], 0b01000000 | 27); // Indexed name
383        assert_eq!(res[1], 0x80 | 2); // header value w/ huffman coding
384
385        assert_eq!("foo", huff_decode(&res[2..4]));
386
387        // Same name, new value should still use incremental
388        let res = encode(&mut encoder, vec![header("content-language", "bar")]);
389        assert_eq!(res[0], 0b01000000 | 27); // Indexed name
390        assert_eq!(res[1], 0x80 | 3); // header value w/ huffman coding
391        assert_eq!("bar", huff_decode(&res[2..5]));
392    }
393
394    #[test]
395    fn test_repeated_headers_are_indexed() {
396        let mut encoder = Encoder::default();
397        let res = encode(&mut encoder, vec![header("foo", "hello")]);
398
399        assert_eq!(&[0b01000000, 0x80 | 2], &res[0..2]);
400        assert_eq!("foo", huff_decode(&res[2..4]));
401        assert_eq!(0x80 | 4, res[4]);
402        assert_eq!("hello", huff_decode(&res[5..]));
403        assert_eq!(9, res.len());
404
405        assert_eq!(1, encoder.table.len());
406
407        let res = encode(&mut encoder, vec![header("foo", "hello")]);
408        assert_eq!([0x80 | 62], *res);
409
410        assert_eq!(encoder.table.len(), 1);
411    }
412
413    #[test]
414    fn test_evicting_headers() {
415        let mut encoder = Encoder::default();
416
417        // Fill the table
418        for i in 0..64 {
419            let key = format!("x-hello-world-{:02}", i);
420            let res = encode(&mut encoder, vec![header(&key, &key)]);
421
422            assert_eq!(&[0b01000000, 0x80 | 12], &res[0..2]);
423            assert_eq!(key, huff_decode(&res[2..14]));
424            assert_eq!(0x80 | 12, res[14]);
425            assert_eq!(key, huff_decode(&res[15..]));
426            assert_eq!(27, res.len());
427
428            // Make sure the header can be found...
429            let res = encode(&mut encoder, vec![header(&key, &key)]);
430
431            // Only check that it is found
432            assert_eq!(0x80, res[0] & 0x80);
433        }
434
435        assert_eq!(4096, encoder.table.size());
436        assert_eq!(64, encoder.table.len());
437
438        // Find existing headers
439        for i in 0..64 {
440            let key = format!("x-hello-world-{:02}", i);
441            let res = encode(&mut encoder, vec![header(&key, &key)]);
442            assert_eq!(0x80, res[0] & 0x80);
443        }
444
445        // Insert a new header
446        let key = "x-hello-world-64";
447        let res = encode(&mut encoder, vec![header(key, key)]);
448
449        assert_eq!(&[0b01000000, 0x80 | 12], &res[0..2]);
450        assert_eq!(key, huff_decode(&res[2..14]));
451        assert_eq!(0x80 | 12, res[14]);
452        assert_eq!(key, huff_decode(&res[15..]));
453        assert_eq!(27, res.len());
454
455        assert_eq!(64, encoder.table.len());
456
457        // Now try encoding entries that should exist in the table
458        for i in 1..65 {
459            let key = format!("x-hello-world-{:02}", i);
460            let res = encode(&mut encoder, vec![header(&key, &key)]);
461            assert_eq!(0x80 | (61 + (65 - i)), res[0]);
462        }
463    }
464
465    #[test]
466    fn test_large_headers_are_not_indexed() {
467        let mut encoder = Encoder::new(128, 0);
468        let key = "hello-world-hello-world-HELLO-zzz";
469
470        let res = encode(&mut encoder, vec![header(key, key)]);
471
472        assert_eq!(&[0, 0x80 | 25], &res[..2]);
473
474        assert_eq!(0, encoder.table.len());
475        assert_eq!(0, encoder.table.size());
476    }
477
478    #[test]
479    fn test_sensitive_headers_are_never_indexed() {
480        use http::header::HeaderValue;
481
482        let name = "my-password".parse().unwrap();
483        let mut value = HeaderValue::from_bytes(b"12345").unwrap();
484        value.set_sensitive(true);
485
486        let header = Header::Field {
487            name: Some(name),
488            value,
489        };
490
491        // Now, try to encode the sensitive header
492
493        let mut encoder = Encoder::default();
494        let res = encode(&mut encoder, vec![header]);
495
496        assert_eq!(&[0b10000, 0x80 | 8], &res[..2]);
497        assert_eq!("my-password", huff_decode(&res[2..10]));
498        assert_eq!(0x80 | 4, res[10]);
499        assert_eq!("12345", huff_decode(&res[11..]));
500
501        // Now, try to encode a sensitive header w/ a name in the static table
502        let name = "authorization".parse().unwrap();
503        let mut value = HeaderValue::from_bytes(b"12345").unwrap();
504        value.set_sensitive(true);
505
506        let header = Header::Field {
507            name: Some(name),
508            value,
509        };
510
511        let mut encoder = Encoder::default();
512        let res = encode(&mut encoder, vec![header]);
513
514        assert_eq!(&[0b11111, 8], &res[..2]);
515        assert_eq!(0x80 | 4, res[2]);
516        assert_eq!("12345", huff_decode(&res[3..]));
517
518        // Using the name component of a previously indexed header (without
519        // sensitive flag set)
520
521        let _ = encode(
522            &mut encoder,
523            vec![self::header("my-password", "not-so-secret")],
524        );
525
526        let name = "my-password".parse().unwrap();
527        let mut value = HeaderValue::from_bytes(b"12345").unwrap();
528        value.set_sensitive(true);
529
530        let header = Header::Field {
531            name: Some(name),
532            value,
533        };
534        let res = encode(&mut encoder, vec![header]);
535
536        assert_eq!(&[0b11111, 47], &res[..2]);
537        assert_eq!(0x80 | 4, res[2]);
538        assert_eq!("12345", huff_decode(&res[3..]));
539    }
540
541    #[test]
542    fn test_content_length_value_not_indexed() {
543        let mut encoder = Encoder::default();
544        let res = encode(&mut encoder, vec![header("content-length", "1234")]);
545
546        assert_eq!(&[15, 13, 0x80 | 3], &res[0..3]);
547        assert_eq!("1234", huff_decode(&res[3..]));
548        assert_eq!(6, res.len());
549    }
550
551    #[test]
552    fn test_encoding_headers_with_same_name() {
553        let mut encoder = Encoder::default();
554        let name = "hello";
555
556        // Encode first one
557        let _ = encode(&mut encoder, vec![header(name, "one")]);
558
559        // Encode second one
560        let res = encode(&mut encoder, vec![header(name, "two")]);
561        assert_eq!(&[0x40 | 62, 0x80 | 3], &res[0..2]);
562        assert_eq!("two", huff_decode(&res[2..]));
563        assert_eq!(5, res.len());
564
565        // Encode the first one again
566        let res = encode(&mut encoder, vec![header(name, "one")]);
567        assert_eq!(&[0x80 | 63], &res[..]);
568
569        // Now the second one
570        let res = encode(&mut encoder, vec![header(name, "two")]);
571        assert_eq!(&[0x80 | 62], &res[..]);
572    }
573
574    #[test]
575    fn test_evicting_headers_when_multiple_of_same_name_are_in_table() {
576        // The encoder only has space for 2 headers
577        let mut encoder = Encoder::new(76, 0);
578
579        let _ = encode(&mut encoder, vec![header("foo", "bar")]);
580        assert_eq!(1, encoder.table.len());
581
582        let _ = encode(&mut encoder, vec![header("bar", "foo")]);
583        assert_eq!(2, encoder.table.len());
584
585        // This will evict the first header, while still referencing the header
586        // name
587        let res = encode(&mut encoder, vec![header("foo", "baz")]);
588        assert_eq!(&[0x40 | 63, 0, 0x80 | 3], &res[..3]);
589        assert_eq!(2, encoder.table.len());
590
591        // Try adding the same header again
592        let res = encode(&mut encoder, vec![header("foo", "baz")]);
593        assert_eq!(&[0x80 | 62], &res[..]);
594        assert_eq!(2, encoder.table.len());
595    }
596
597    #[test]
598    fn test_max_size_zero() {
599        // Static table only
600        let mut encoder = Encoder::new(0, 0);
601        let res = encode(&mut encoder, vec![method("GET")]);
602        assert_eq!(*res, [0x80 | 2]);
603        assert_eq!(encoder.table.len(), 0);
604
605        let res = encode(&mut encoder, vec![header("foo", "bar")]);
606        assert_eq!(&[0, 0x80 | 2], &res[..2]);
607        assert_eq!("foo", huff_decode(&res[2..4]));
608        assert_eq!(0x80 | 3, res[4]);
609        assert_eq!("bar", huff_decode(&res[5..8]));
610        assert_eq!(0, encoder.table.len());
611
612        // Encode a custom value
613        let res = encode(&mut encoder, vec![header("transfer-encoding", "chunked")]);
614        assert_eq!(&[15, 42, 0x80 | 6], &res[..3]);
615        assert_eq!("chunked", huff_decode(&res[3..]));
616    }
617
618    #[test]
619    fn test_update_max_size_combos() {
620        let mut encoder = Encoder::default();
621        assert!(encoder.size_update.is_none());
622        assert_eq!(4096, encoder.table.max_size());
623
624        encoder.update_max_size(4096); // Default size
625        assert!(encoder.size_update.is_none());
626
627        encoder.update_max_size(0);
628        assert_eq!(Some(SizeUpdate::One(0)), encoder.size_update);
629
630        encoder.update_max_size(100);
631        assert_eq!(Some(SizeUpdate::Two(0, 100)), encoder.size_update);
632
633        let mut encoder = Encoder::default();
634        encoder.set_max_allowed_size(8000);
635        encoder.update_max_size(8000);
636        assert_eq!(Some(SizeUpdate::One(8000)), encoder.size_update);
637
638        encoder.update_max_size(100);
639        assert_eq!(Some(SizeUpdate::One(100)), encoder.size_update);
640
641        encoder.update_max_size(8000);
642        assert_eq!(Some(SizeUpdate::Two(100, 8000)), encoder.size_update);
643
644        encoder.update_max_size(4000);
645        assert_eq!(Some(SizeUpdate::Two(100, 4000)), encoder.size_update);
646
647        encoder.update_max_size(50);
648        assert_eq!(Some(SizeUpdate::One(50)), encoder.size_update);
649    }
650
651    #[test]
652    fn test_resizing_table() {
653        let mut encoder = Encoder::default();
654
655        // Add a header
656        let _ = encode(&mut encoder, vec![header("foo", "bar")]);
657
658        encoder.update_max_size(1);
659        assert_eq!(1, encoder.table.len());
660
661        let res = encode(&mut encoder, vec![method("GET")]);
662        assert_eq!(&[32 | 1, 0x80 | 2], &res[..]);
663        assert_eq!(0, encoder.table.len());
664
665        let res = encode(&mut encoder, vec![header("foo", "bar")]);
666        assert_eq!(0, res[0]);
667
668        encoder.update_max_size(100);
669        let res = encode(&mut encoder, vec![header("foo", "bar")]);
670        assert_eq!(&[32 | 31, 69, 64], &res[..3]);
671
672        encoder.update_max_size(0);
673        let res = encode(&mut encoder, vec![header("foo", "bar")]);
674        assert_eq!(&[32, 0], &res[..2]);
675    }
676
677    #[test]
678    fn test_decreasing_table_size_without_eviction() {
679        let mut encoder = Encoder::default();
680
681        // Add a header
682        let _ = encode(&mut encoder, vec![header("foo", "bar")]);
683
684        encoder.update_max_size(100);
685        assert_eq!(1, encoder.table.len());
686
687        let res = encode(&mut encoder, vec![header("foo", "bar")]);
688        assert_eq!(&[32 | 31, 69, 0x80 | 62], &res[..]);
689    }
690
691    #[test]
692    fn test_nameless_header() {
693        let mut encoder = Encoder::default();
694
695        let res = encode(
696            &mut encoder,
697            vec![
698                Header::Field {
699                    name: Some("hello".parse().unwrap()),
700                    value: HeaderValue::from_bytes(b"world").unwrap(),
701                },
702                Header::Field {
703                    name: None,
704                    value: HeaderValue::from_bytes(b"zomg").unwrap(),
705                },
706            ],
707        );
708
709        assert_eq!(&[0x40, 0x80 | 4], &res[0..2]);
710        assert_eq!("hello", huff_decode(&res[2..6]));
711        assert_eq!(0x80 | 4, res[6]);
712        assert_eq!("world", huff_decode(&res[7..11]));
713
714        // Next is not indexed
715        assert_eq!(&[15, 47, 0x80 | 3], &res[11..14]);
716        assert_eq!("zomg", huff_decode(&res[14..]));
717    }
718
719    #[test]
720    fn test_large_size_update() {
721        let mut encoder = Encoder::default();
722        encoder.set_max_allowed_size(usize::MAX);
723
724        encoder.update_max_size(1912930560);
725        assert_eq!(Some(SizeUpdate::One(1912930560)), encoder.size_update);
726
727        let mut dst = BytesMut::with_capacity(6);
728        encoder.encode_size_updates(&mut dst);
729        assert_eq!([63, 225, 129, 148, 144, 7], &dst[..]);
730    }
731
732    #[test]
733    fn test_large_size_update_is_capped() {
734        let mut encoder = Encoder::new(0, 0);
735
736        encoder.update_max_size(1912930560);
737        assert_eq!(
738            Some(SizeUpdate::One(DEFAULT_MAX_ALLOWED_SIZE)),
739            encoder.size_update
740        );
741
742        let mut dst = BytesMut::with_capacity(3);
743        encoder.encode_size_updates(&mut dst);
744        assert_eq!([63, 225, 31], &dst[..]);
745        assert_eq!(DEFAULT_MAX_ALLOWED_SIZE, encoder.table.max_size());
746    }
747
748    #[test]
749    #[ignore]
750    fn test_evicted_overflow() {
751        // Not sure what the best way to do this is.
752    }
753
754    fn encode(e: &mut Encoder, hdrs: Vec<Header<Option<HeaderName>>>) -> BytesMut {
755        let mut dst = BytesMut::with_capacity(1024);
756        e.encode(hdrs, &mut dst);
757        dst
758    }
759
760    fn method(s: &str) -> Header<Option<HeaderName>> {
761        Header::Method(Method::from_bytes(s.as_bytes()).unwrap())
762    }
763
764    fn header(name: &str, val: &str) -> Header<Option<HeaderName>> {
765        let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
766        let value = HeaderValue::from_bytes(val.as_bytes()).unwrap();
767
768        Header::Field {
769            name: Some(name),
770            value,
771        }
772    }
773
774    fn huff_decode(src: &[u8]) -> BytesMut {
775        let mut buf = BytesMut::new();
776        huffman::decode(src, &mut buf).unwrap()
777    }
778}