Skip to main content

h2/frame/
headers.rs

1use super::{util, StreamDependency, StreamId};
2use crate::ext::Protocol;
3use crate::frame::{Error, Frame, Head, Kind};
4use crate::hpack::{self, BytesStr};
5
6use http::header::{self, HeaderName, HeaderValue};
7use http::{uri, HeaderMap, Method, Request, StatusCode, Uri};
8
9use bytes::{Buf, BufMut, BytesMut};
10
11use std::fmt;
12use std::io::Cursor;
13use std::ops::ControlFlow;
14
15type EncodeBuf<'a> = bytes::buf::Limit<&'a mut BytesMut>;
16
17const MAX_HEADER_LIST_ABUSE_MULTIPLIER: usize = 4;
18
19/// Header frame
20///
21/// This could be either a request or a response.
22#[derive(Eq, PartialEq)]
23pub struct Headers {
24    /// The ID of the stream with which this frame is associated.
25    stream_id: StreamId,
26
27    /// The stream dependency information, if any.
28    stream_dep: Option<StreamDependency>,
29
30    /// The header block fragment
31    header_block: HeaderBlock,
32
33    /// The associated flags
34    flags: HeadersFlag,
35}
36
37#[derive(Copy, Clone, Eq, PartialEq)]
38pub struct HeadersFlag(u8);
39
40#[derive(Eq, PartialEq)]
41pub struct PushPromise {
42    /// The ID of the stream with which this frame is associated.
43    stream_id: StreamId,
44
45    /// The ID of the stream being reserved by this PushPromise.
46    promised_id: StreamId,
47
48    /// The header block fragment
49    header_block: HeaderBlock,
50
51    /// The associated flags
52    flags: PushPromiseFlag,
53}
54
55#[derive(Copy, Clone, Eq, PartialEq)]
56pub struct PushPromiseFlag(u8);
57
58#[derive(Debug)]
59pub struct Continuation {
60    /// Stream ID of continuation frame
61    stream_id: StreamId,
62
63    header_block: EncodingHeaderBlock,
64}
65
66// TODO: These fields shouldn't be `pub`
67#[derive(Debug, Default, Eq, PartialEq)]
68pub struct Pseudo {
69    // Request
70    pub method: Option<Method>,
71    pub scheme: Option<BytesStr>,
72    pub authority: Option<BytesStr>,
73    pub path: Option<BytesStr>,
74    pub protocol: Option<Protocol>,
75
76    // Response
77    pub status: Option<StatusCode>,
78}
79
80#[derive(Debug)]
81pub struct Iter {
82    /// Pseudo headers
83    pseudo: Option<Pseudo>,
84
85    /// Header fields
86    fields: header::IntoIter<HeaderValue>,
87}
88
89#[derive(Debug, PartialEq, Eq)]
90struct HeaderBlock {
91    /// The decoded header fields
92    fields: HeaderMap,
93
94    /// Precomputed size of all of our header fields, for perf reasons
95    field_size: usize,
96
97    /// Set to true if decoding went over the max header list size.
98    is_over_size: bool,
99
100    /// Pseudo headers, these are broken out as they must be sent as part of the
101    /// headers frame.
102    pseudo: Pseudo,
103}
104
105#[derive(Debug)]
106struct EncodingHeaderBlock {
107    hpack: BytesMut,
108}
109
110const END_STREAM: u8 = 0x1;
111const END_HEADERS: u8 = 0x4;
112const PADDED: u8 = 0x8;
113const PRIORITY: u8 = 0x20;
114const ALL: u8 = END_STREAM | END_HEADERS | PADDED | PRIORITY;
115
116// ===== impl Headers =====
117
118impl Headers {
119    /// Create a new HEADERS frame
120    pub fn new(stream_id: StreamId, pseudo: Pseudo, fields: HeaderMap) -> Self {
121        Headers {
122            stream_id,
123            stream_dep: None,
124            header_block: HeaderBlock {
125                field_size: calculate_headermap_size(&fields),
126                fields,
127                is_over_size: false,
128                pseudo,
129            },
130            flags: HeadersFlag::default(),
131        }
132    }
133
134    pub fn trailers(stream_id: StreamId, fields: HeaderMap) -> Self {
135        let mut flags = HeadersFlag::default();
136        flags.set_end_stream();
137
138        Headers {
139            stream_id,
140            stream_dep: None,
141            header_block: HeaderBlock {
142                field_size: calculate_headermap_size(&fields),
143                fields,
144                is_over_size: false,
145                pseudo: Pseudo::default(),
146            },
147            flags,
148        }
149    }
150
151    /// Loads the header frame but doesn't actually do HPACK decoding.
152    ///
153    /// HPACK decoding is done in the `load_hpack` step.
154    pub fn load(head: Head, mut src: BytesMut) -> Result<(Self, BytesMut), Error> {
155        let flags = HeadersFlag(head.flag());
156        let mut pad = 0;
157
158        tracing::trace!("loading headers; flags={:?}", flags);
159
160        if head.stream_id().is_zero() {
161            return Err(Error::InvalidStreamId);
162        }
163
164        // Read the padding length
165        if flags.is_padded() {
166            if src.is_empty() {
167                return Err(Error::MalformedMessage);
168            }
169            pad = src[0] as usize;
170
171            // Drop the padding
172            src.advance(1);
173        }
174
175        // Read the stream dependency
176        let stream_dep = if flags.is_priority() {
177            if src.len() < 5 {
178                return Err(Error::MalformedMessage);
179            }
180            let stream_dep = StreamDependency::load(&src[..5])?;
181
182            if stream_dep.dependency_id() == head.stream_id() {
183                return Err(Error::InvalidDependencyId);
184            }
185
186            // Drop the next 5 bytes
187            src.advance(5);
188
189            Some(stream_dep)
190        } else {
191            None
192        };
193
194        if pad > 0 {
195            if pad > src.len() {
196                return Err(Error::TooMuchPadding);
197            }
198
199            let len = src.len() - pad;
200            src.truncate(len);
201        }
202
203        let headers = Headers {
204            stream_id: head.stream_id(),
205            stream_dep,
206            header_block: HeaderBlock {
207                fields: HeaderMap::new(),
208                field_size: 0,
209                is_over_size: false,
210                pseudo: Pseudo::default(),
211            },
212            flags,
213        };
214
215        Ok((headers, src))
216    }
217
218    pub fn load_hpack(
219        &mut self,
220        src: &mut BytesMut,
221        max_header_list_size: usize,
222        decoder: &mut hpack::Decoder,
223    ) -> Result<(), Error> {
224        self.header_block.load(src, max_header_list_size, decoder)
225    }
226
227    pub fn stream_id(&self) -> StreamId {
228        self.stream_id
229    }
230
231    pub fn is_end_headers(&self) -> bool {
232        self.flags.is_end_headers()
233    }
234
235    pub fn set_end_headers(&mut self) {
236        self.flags.set_end_headers();
237    }
238
239    pub fn is_end_stream(&self) -> bool {
240        self.flags.is_end_stream()
241    }
242
243    pub fn set_end_stream(&mut self) {
244        self.flags.set_end_stream()
245    }
246
247    pub fn is_over_size(&self) -> bool {
248        self.header_block.is_over_size
249    }
250
251    pub fn into_parts(self) -> (Pseudo, HeaderMap) {
252        (self.header_block.pseudo, self.header_block.fields)
253    }
254
255    #[cfg(feature = "unstable")]
256    pub fn pseudo_mut(&mut self) -> &mut Pseudo {
257        &mut self.header_block.pseudo
258    }
259
260    pub(crate) fn pseudo(&self) -> &Pseudo {
261        &self.header_block.pseudo
262    }
263
264    /// Whether it has status 1xx
265    pub(crate) fn is_informational(&self) -> bool {
266        self.header_block.pseudo.is_informational()
267    }
268
269    pub fn fields(&self) -> &HeaderMap {
270        &self.header_block.fields
271    }
272
273    pub fn into_fields(self) -> HeaderMap {
274        self.header_block.fields
275    }
276
277    pub fn encode(
278        self,
279        encoder: &mut hpack::Encoder,
280        dst: &mut EncodeBuf<'_>,
281    ) -> Option<Continuation> {
282        // At this point, the `is_end_headers` flag should always be set
283        debug_assert!(self.flags.is_end_headers());
284
285        // Get the HEADERS frame head
286        let head = self.head();
287
288        self.header_block
289            .into_encoding(encoder)
290            .encode(&head, dst, Some(encoder), |_| {})
291    }
292
293    fn head(&self) -> Head {
294        Head::new(Kind::Headers, self.flags.into(), self.stream_id)
295    }
296}
297
298impl<T> From<Headers> for Frame<T> {
299    fn from(src: Headers) -> Self {
300        Frame::Headers(src)
301    }
302}
303
304impl fmt::Debug for Headers {
305    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306        let mut builder = f.debug_struct("Headers");
307        builder
308            .field("stream_id", &self.stream_id)
309            .field("flags", &self.flags);
310
311        if let Some(ref protocol) = self.header_block.pseudo.protocol {
312            builder.field("protocol", protocol);
313        }
314
315        if let Some(ref dep) = self.stream_dep {
316            builder.field("stream_dep", dep);
317        }
318
319        // `fields` and `pseudo` purposefully not included
320        builder.finish()
321    }
322}
323
324// ===== util =====
325
326#[derive(Debug, PartialEq, Eq)]
327pub struct ParseU64Error;
328
329pub fn parse_u64(src: &[u8]) -> Result<u64, ParseU64Error> {
330    if src.len() > 19 {
331        // At danger for overflow...
332        return Err(ParseU64Error);
333    }
334
335    let mut ret = 0;
336
337    for &d in src {
338        if d < b'0' || d > b'9' {
339            return Err(ParseU64Error);
340        }
341
342        ret *= 10;
343        ret += (d - b'0') as u64;
344    }
345
346    Ok(ret)
347}
348
349// ===== impl PushPromise =====
350
351#[derive(Debug)]
352pub enum PushPromiseHeaderError {
353    InvalidContentLength(Result<u64, ParseU64Error>),
354    NotSafeAndCacheable,
355}
356
357impl PushPromise {
358    pub fn new(
359        stream_id: StreamId,
360        promised_id: StreamId,
361        pseudo: Pseudo,
362        fields: HeaderMap,
363    ) -> Self {
364        PushPromise {
365            flags: PushPromiseFlag::default(),
366            header_block: HeaderBlock {
367                field_size: calculate_headermap_size(&fields),
368                fields,
369                is_over_size: false,
370                pseudo,
371            },
372            promised_id,
373            stream_id,
374        }
375    }
376
377    pub fn validate_request(req: &Request<()>) -> Result<(), PushPromiseHeaderError> {
378        use PushPromiseHeaderError::*;
379        // The spec has some requirements for promised request headers
380        // [https://httpwg.org/specs/rfc7540.html#PushRequests]
381
382        // A promised request "that indicates the presence of a request body
383        // MUST reset the promised stream with a stream error"
384        if let Some(content_length) = req.headers().get(header::CONTENT_LENGTH) {
385            let parsed_length = parse_u64(content_length.as_bytes());
386            if parsed_length != Ok(0) {
387                return Err(InvalidContentLength(parsed_length));
388            }
389        }
390        // "The server MUST include a method in the :method pseudo-header field
391        // that is safe and cacheable"
392        if !Self::safe_and_cacheable(req.method()) {
393            return Err(NotSafeAndCacheable);
394        }
395
396        Ok(())
397    }
398
399    fn safe_and_cacheable(method: &Method) -> bool {
400        // Cacheable: https://httpwg.org/specs/rfc7231.html#cacheable.methods
401        // Safe: https://httpwg.org/specs/rfc7231.html#safe.methods
402        method == Method::GET || method == Method::HEAD
403    }
404
405    pub fn fields(&self) -> &HeaderMap {
406        &self.header_block.fields
407    }
408
409    #[cfg(feature = "unstable")]
410    pub fn into_fields(self) -> HeaderMap {
411        self.header_block.fields
412    }
413
414    /// Loads the push promise frame but doesn't actually do HPACK decoding.
415    ///
416    /// HPACK decoding is done in the `load_hpack` step.
417    pub fn load(head: Head, mut src: BytesMut) -> Result<(Self, BytesMut), Error> {
418        let flags = PushPromiseFlag(head.flag());
419        let mut pad = 0;
420
421        if head.stream_id().is_zero() {
422            return Err(Error::InvalidStreamId);
423        }
424
425        // Read the padding length
426        if flags.is_padded() {
427            if src.is_empty() {
428                return Err(Error::MalformedMessage);
429            }
430
431            // TODO: Ensure payload is sized correctly
432            pad = src[0] as usize;
433
434            // Drop the padding
435            src.advance(1);
436        }
437
438        if src.len() < 5 {
439            return Err(Error::MalformedMessage);
440        }
441
442        let (promised_id, _) = StreamId::parse(&src[..4]);
443        // Drop promised_id bytes
444        src.advance(4);
445
446        if pad > 0 {
447            if pad > src.len() {
448                return Err(Error::TooMuchPadding);
449            }
450
451            let len = src.len() - pad;
452            src.truncate(len);
453        }
454
455        let frame = PushPromise {
456            flags,
457            header_block: HeaderBlock {
458                fields: HeaderMap::new(),
459                field_size: 0,
460                is_over_size: false,
461                pseudo: Pseudo::default(),
462            },
463            promised_id,
464            stream_id: head.stream_id(),
465        };
466        Ok((frame, src))
467    }
468
469    pub fn load_hpack(
470        &mut self,
471        src: &mut BytesMut,
472        max_header_list_size: usize,
473        decoder: &mut hpack::Decoder,
474    ) -> Result<(), Error> {
475        self.header_block.load(src, max_header_list_size, decoder)
476    }
477
478    pub fn stream_id(&self) -> StreamId {
479        self.stream_id
480    }
481
482    pub fn promised_id(&self) -> StreamId {
483        self.promised_id
484    }
485
486    pub fn is_end_headers(&self) -> bool {
487        self.flags.is_end_headers()
488    }
489
490    pub fn set_end_headers(&mut self) {
491        self.flags.set_end_headers();
492    }
493
494    pub fn is_over_size(&self) -> bool {
495        self.header_block.is_over_size
496    }
497
498    pub fn encode(
499        self,
500        encoder: &mut hpack::Encoder,
501        dst: &mut EncodeBuf<'_>,
502    ) -> Option<Continuation> {
503        // At this point, the `is_end_headers` flag should always be set
504        debug_assert!(self.flags.is_end_headers());
505
506        let head = self.head();
507        let promised_id = self.promised_id;
508
509        self.header_block
510            .into_encoding(encoder)
511            .encode(&head, dst, Some(encoder), |dst| {
512                dst.put_u32(promised_id.into());
513            })
514    }
515
516    fn head(&self) -> Head {
517        Head::new(Kind::PushPromise, self.flags.into(), self.stream_id)
518    }
519
520    /// Consume `self`, returning the parts of the frame
521    pub fn into_parts(self) -> (Pseudo, HeaderMap) {
522        (self.header_block.pseudo, self.header_block.fields)
523    }
524}
525
526impl<T> From<PushPromise> for Frame<T> {
527    fn from(src: PushPromise) -> Self {
528        Frame::PushPromise(src)
529    }
530}
531
532impl fmt::Debug for PushPromise {
533    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534        f.debug_struct("PushPromise")
535            .field("stream_id", &self.stream_id)
536            .field("promised_id", &self.promised_id)
537            .field("flags", &self.flags)
538            // `fields` and `pseudo` purposefully not included
539            .finish()
540    }
541}
542
543// ===== impl Continuation =====
544
545impl Continuation {
546    fn head(&self) -> Head {
547        Head::new(Kind::Continuation, END_HEADERS, self.stream_id)
548    }
549
550    pub fn encode(self, dst: &mut EncodeBuf<'_>) -> Option<Continuation> {
551        // Get the CONTINUATION frame head
552        let head = self.head();
553
554        self.header_block.encode(&head, dst, None, |_| {})
555    }
556}
557
558// ===== impl Pseudo =====
559
560impl Pseudo {
561    pub fn request(method: Method, uri: Uri, protocol: Option<Protocol>) -> Self {
562        let parts = uri::Parts::from(uri);
563
564        let (scheme, path) = if method == Method::CONNECT && protocol.is_none() {
565            (None, None)
566        } else {
567            let path = parts
568                .path_and_query
569                .map(|v| BytesStr::from(v.as_str()))
570                .unwrap_or(BytesStr::from_static(""));
571
572            let path = if !path.is_empty() {
573                path
574            } else if method == Method::OPTIONS {
575                BytesStr::from_static("*")
576            } else {
577                BytesStr::from_static("/")
578            };
579
580            (parts.scheme, Some(path))
581        };
582
583        let mut pseudo = Pseudo {
584            method: Some(method),
585            scheme: None,
586            authority: None,
587            path,
588            protocol,
589            status: None,
590        };
591
592        // If the URI includes a scheme component, add it to the pseudo headers
593        if let Some(scheme) = scheme {
594            pseudo.set_scheme(scheme);
595        }
596
597        // If the URI includes an authority component, add it to the pseudo
598        // headers
599        if let Some(authority) = parts.authority {
600            pseudo.set_authority(BytesStr::from(authority.as_str()));
601        }
602
603        pseudo
604    }
605
606    pub fn response(status: StatusCode) -> Self {
607        Pseudo {
608            method: None,
609            scheme: None,
610            authority: None,
611            path: None,
612            protocol: None,
613            status: Some(status),
614        }
615    }
616
617    #[cfg(feature = "unstable")]
618    pub fn set_status(&mut self, value: StatusCode) {
619        self.status = Some(value);
620    }
621
622    pub fn set_scheme(&mut self, scheme: uri::Scheme) {
623        let bytes_str = match scheme.as_str() {
624            "http" => BytesStr::from_static("http"),
625            "https" => BytesStr::from_static("https"),
626            s => BytesStr::from(s),
627        };
628        self.scheme = Some(bytes_str);
629    }
630
631    #[cfg(feature = "unstable")]
632    pub fn set_protocol(&mut self, protocol: Protocol) {
633        self.protocol = Some(protocol);
634    }
635
636    pub fn set_authority(&mut self, authority: BytesStr) {
637        self.authority = Some(authority);
638    }
639
640    /// Whether it has status 1xx
641    pub(crate) fn is_informational(&self) -> bool {
642        self.status
643            .map_or(false, |status| status.is_informational())
644    }
645}
646
647// ===== impl EncodingHeaderBlock =====
648
649impl EncodingHeaderBlock {
650    fn encode<F>(
651        mut self,
652        head: &Head,
653        dst: &mut EncodeBuf<'_>,
654        encoder: Option<&mut hpack::Encoder>,
655        f: F,
656    ) -> Option<Continuation>
657    where
658        F: FnOnce(&mut EncodeBuf<'_>),
659    {
660        let head_pos = dst.get_ref().len();
661
662        // At this point, we don't know how big the h2 frame will be.
663        // So, we write the head with length 0, then write the body, and
664        // finally write the length once we know the size.
665        head.encode(0, dst);
666
667        let payload_pos = dst.get_ref().len();
668
669        f(dst);
670
671        // Now, encode the header payload
672        let continuation = if self.hpack.len() > dst.remaining_mut() {
673            let head_part = self.hpack.split_to(dst.remaining_mut());
674            dst.put_slice(&head_part);
675
676            Some(Continuation {
677                stream_id: head.stream_id(),
678                header_block: self,
679            })
680        } else {
681            dst.put_slice(&self.hpack);
682            // The block is fully written, so the buffer can be reused by the
683            // next frame on this connection.
684            if let Some(encoder) = encoder {
685                encoder.return_scratch(self.hpack);
686            }
687
688            None
689        };
690
691        // Compute the header block length
692        let payload_len = (dst.get_ref().len() - payload_pos) as u64;
693
694        // Write the frame length
695        let payload_len_be = payload_len.to_be_bytes();
696        assert!(payload_len_be[0..5].iter().all(|b| *b == 0));
697        (dst.get_mut()[head_pos..head_pos + 3]).copy_from_slice(&payload_len_be[5..]);
698
699        if continuation.is_some() {
700            // There will be continuation frames, so the `is_end_headers` flag
701            // must be unset
702            debug_assert!(dst.get_ref()[head_pos + 4] & END_HEADERS == END_HEADERS);
703
704            dst.get_mut()[head_pos + 4] -= END_HEADERS;
705        }
706
707        continuation
708    }
709}
710
711// ===== impl Iter =====
712
713impl Iterator for Iter {
714    type Item = hpack::Header<Option<HeaderName>>;
715
716    fn next(&mut self) -> Option<Self::Item> {
717        use crate::hpack::Header::*;
718
719        if let Some(ref mut pseudo) = self.pseudo {
720            if let Some(method) = pseudo.method.take() {
721                return Some(Method(method));
722            }
723
724            if let Some(scheme) = pseudo.scheme.take() {
725                return Some(Scheme(scheme));
726            }
727
728            if let Some(authority) = pseudo.authority.take() {
729                return Some(Authority(authority));
730            }
731
732            if let Some(path) = pseudo.path.take() {
733                return Some(Path(path));
734            }
735
736            if let Some(protocol) = pseudo.protocol.take() {
737                return Some(Protocol(protocol));
738            }
739
740            if let Some(status) = pseudo.status.take() {
741                return Some(Status(status));
742            }
743        }
744
745        self.pseudo = None;
746
747        self.fields
748            .next()
749            .map(|(name, value)| Field { name, value })
750    }
751}
752
753// ===== impl HeadersFlag =====
754
755impl HeadersFlag {
756    pub fn empty() -> HeadersFlag {
757        HeadersFlag(0)
758    }
759
760    pub fn load(bits: u8) -> HeadersFlag {
761        HeadersFlag(bits & ALL)
762    }
763
764    pub fn is_end_stream(&self) -> bool {
765        self.0 & END_STREAM == END_STREAM
766    }
767
768    pub fn set_end_stream(&mut self) {
769        self.0 |= END_STREAM;
770    }
771
772    pub fn is_end_headers(&self) -> bool {
773        self.0 & END_HEADERS == END_HEADERS
774    }
775
776    pub fn set_end_headers(&mut self) {
777        self.0 |= END_HEADERS;
778    }
779
780    pub fn is_padded(&self) -> bool {
781        self.0 & PADDED == PADDED
782    }
783
784    pub fn is_priority(&self) -> bool {
785        self.0 & PRIORITY == PRIORITY
786    }
787}
788
789impl Default for HeadersFlag {
790    /// Returns a `HeadersFlag` value with `END_HEADERS` set.
791    fn default() -> Self {
792        HeadersFlag(END_HEADERS)
793    }
794}
795
796impl From<HeadersFlag> for u8 {
797    fn from(src: HeadersFlag) -> u8 {
798        src.0
799    }
800}
801
802impl fmt::Debug for HeadersFlag {
803    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
804        util::debug_flags(fmt, self.0)
805            .flag_if(self.is_end_headers(), "END_HEADERS")
806            .flag_if(self.is_end_stream(), "END_STREAM")
807            .flag_if(self.is_padded(), "PADDED")
808            .flag_if(self.is_priority(), "PRIORITY")
809            .finish()
810    }
811}
812
813// ===== impl PushPromiseFlag =====
814
815impl PushPromiseFlag {
816    pub fn empty() -> PushPromiseFlag {
817        PushPromiseFlag(0)
818    }
819
820    pub fn load(bits: u8) -> PushPromiseFlag {
821        PushPromiseFlag(bits & ALL)
822    }
823
824    pub fn is_end_headers(&self) -> bool {
825        self.0 & END_HEADERS == END_HEADERS
826    }
827
828    pub fn set_end_headers(&mut self) {
829        self.0 |= END_HEADERS;
830    }
831
832    pub fn is_padded(&self) -> bool {
833        self.0 & PADDED == PADDED
834    }
835}
836
837impl Default for PushPromiseFlag {
838    /// Returns a `PushPromiseFlag` value with `END_HEADERS` set.
839    fn default() -> Self {
840        PushPromiseFlag(END_HEADERS)
841    }
842}
843
844impl From<PushPromiseFlag> for u8 {
845    fn from(src: PushPromiseFlag) -> u8 {
846        src.0
847    }
848}
849
850impl fmt::Debug for PushPromiseFlag {
851    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
852        util::debug_flags(fmt, self.0)
853            .flag_if(self.is_end_headers(), "END_HEADERS")
854            .flag_if(self.is_padded(), "PADDED")
855            .finish()
856    }
857}
858
859// ===== HeaderBlock =====
860
861impl HeaderBlock {
862    fn load(
863        &mut self,
864        src: &mut BytesMut,
865        max_header_list_size: usize,
866        decoder: &mut hpack::Decoder,
867    ) -> Result<(), Error> {
868        let mut reg = !self.fields.is_empty();
869        let mut malformed = false;
870        let mut header_list_way_too_large = false;
871        let mut headers_size = self.calculate_header_list_size();
872        let max_header_list_abuse_size =
873            max_header_list_size.saturating_mul(MAX_HEADER_LIST_ABUSE_MULTIPLIER);
874
875        macro_rules! check_size {
876            () => {{
877                if headers_size > max_header_list_abuse_size {
878                    tracing::trace!("load_hpack; header list size over abuse max");
879                    header_list_way_too_large = true;
880                    ControlFlow::Break(())
881                } else {
882                    if headers_size >= max_header_list_size && !self.is_over_size {
883                        tracing::trace!("load_hpack; header list size over max");
884                        self.is_over_size = true;
885                    }
886                    ControlFlow::Continue(())
887                }
888            }};
889        }
890
891        macro_rules! set_pseudo {
892            ($field:ident, $val:expr) => {{
893                if reg {
894                    tracing::trace!("load_hpack; header malformed -- pseudo not at head of block");
895                    malformed = true;
896                } else if self.pseudo.$field.is_some() {
897                    tracing::trace!("load_hpack; header malformed -- repeated pseudo");
898                    malformed = true;
899                } else {
900                    let __val = $val;
901                    headers_size +=
902                        decoded_header_size(stringify!($field).len() + 1, __val.as_str().len());
903                    if check_size!().is_break() {
904                        return ControlFlow::Break(());
905                    }
906                    if !self.is_over_size {
907                        self.pseudo.$field = Some(__val);
908                    }
909                }
910            }};
911        }
912
913        let mut cursor = Cursor::new(src);
914
915        // If the header frame is malformed, we still have to continue decoding
916        // the headers. A malformed header frame is a stream level error, but
917        // the hpack state is connection level. In order to maintain correct
918        // state for other streams, the hpack decoding process must complete.
919        let res = decoder.decode(&mut cursor, |header| {
920            use crate::hpack::Header::*;
921
922            match header {
923                Field { name, value } => {
924                    // Connection level header fields are not supported and must
925                    // result in a protocol error.
926
927                    if name == header::CONNECTION
928                        || name == header::TRANSFER_ENCODING
929                        || name == header::UPGRADE
930                        || name == "keep-alive"
931                        || name == "proxy-connection"
932                    {
933                        tracing::trace!("load_hpack; connection level header");
934                        malformed = true;
935                    } else if name == header::TE && value != "trailers" {
936                        tracing::trace!(
937                            "load_hpack; TE header not set to trailers; val={:?}",
938                            value
939                        );
940                        malformed = true;
941                    } else {
942                        reg = true;
943
944                        let header_size = decoded_header_size(name.as_str().len(), value.len());
945                        headers_size += header_size;
946                        if check_size!().is_break() {
947                            return ControlFlow::Break(());
948                        }
949                        if !self.is_over_size {
950                            self.field_size += header_size;
951                            if let Err(_) = self.fields.try_append(name, value) {
952                                // HeaderMap capacity exceeded — treat as over-size
953                                // so the stream is rejected downstream (RST_STREAM / 431)
954                                // instead of panicking on the 24,577th unique header.
955                                self.is_over_size = true;
956                            }
957                        }
958                    }
959                }
960                Authority(v) => set_pseudo!(authority, v),
961                Method(v) => set_pseudo!(method, v),
962                Scheme(v) => set_pseudo!(scheme, v),
963                Path(v) => set_pseudo!(path, v),
964                Protocol(v) => set_pseudo!(protocol, v),
965                Status(v) => set_pseudo!(status, v),
966            }
967
968            ControlFlow::Continue(())
969        });
970
971        match res {
972            Ok(()) => {}
973            Err(e) => {
974                tracing::trace!("hpack decoding error; err={:?}", e);
975                return Err(e.into());
976            }
977        }
978
979        if header_list_way_too_large {
980            tracing::trace!("header list way too large; aborting connection");
981            return Err(Error::HeaderListWayTooLarge);
982        }
983
984        if malformed {
985            tracing::trace!("malformed message");
986            return Err(Error::MalformedMessage);
987        }
988
989        Ok(())
990    }
991
992    fn into_encoding(self, encoder: &mut hpack::Encoder) -> EncodingHeaderBlock {
993        let mut hpack = encoder.take_scratch();
994        hpack.clear();
995        let headers = Iter {
996            pseudo: Some(self.pseudo),
997            fields: self.fields.into_iter(),
998        };
999
1000        encoder.encode(headers, &mut hpack);
1001
1002        EncodingHeaderBlock { hpack }
1003    }
1004
1005    /// Calculates the size of the currently decoded header list.
1006    ///
1007    /// According to http://httpwg.org/specs/rfc7540.html#SETTINGS_MAX_HEADER_LIST_SIZE
1008    ///
1009    /// > The value is based on the uncompressed size of header fields,
1010    /// > including the length of the name and value in octets plus an
1011    /// > overhead of 32 octets for each header field.
1012    fn calculate_header_list_size(&self) -> usize {
1013        macro_rules! pseudo_size {
1014            ($name:ident) => {{
1015                self.pseudo
1016                    .$name
1017                    .as_ref()
1018                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
1019                    .unwrap_or(0)
1020            }};
1021        }
1022
1023        pseudo_size!(method)
1024            + pseudo_size!(scheme)
1025            + pseudo_size!(status)
1026            + pseudo_size!(authority)
1027            + pseudo_size!(path)
1028            + self.field_size
1029    }
1030}
1031
1032fn calculate_headermap_size(map: &HeaderMap) -> usize {
1033    map.iter()
1034        .map(|(name, value)| decoded_header_size(name.as_str().len(), value.len()))
1035        .sum::<usize>()
1036}
1037
1038fn decoded_header_size(name: usize, value: usize) -> usize {
1039    name + value + 32
1040}
1041
1042#[cfg(test)]
1043mod test {
1044    use super::*;
1045    use crate::frame;
1046    use crate::hpack::{huffman, Encoder};
1047
1048    #[test]
1049    fn test_nameless_header_at_resume() {
1050        let mut encoder = Encoder::default();
1051        let mut dst = BytesMut::new();
1052
1053        let headers = Headers::new(
1054            StreamId::ZERO,
1055            Default::default(),
1056            HeaderMap::from_iter(vec![
1057                (
1058                    HeaderName::from_static("hello"),
1059                    HeaderValue::from_static("world"),
1060                ),
1061                (
1062                    HeaderName::from_static("hello"),
1063                    HeaderValue::from_static("zomg"),
1064                ),
1065                (
1066                    HeaderName::from_static("hello"),
1067                    HeaderValue::from_static("sup"),
1068                ),
1069            ]),
1070        );
1071
1072        let continuation = headers
1073            .encode(&mut encoder, &mut (&mut dst).limit(frame::HEADER_LEN + 8))
1074            .unwrap();
1075
1076        assert_eq!(17, dst.len());
1077        assert_eq!([0, 0, 8, 1, 0, 0, 0, 0, 0], &dst[0..9]);
1078        assert_eq!(&[0x40, 0x80 | 4], &dst[9..11]);
1079        assert_eq!("hello", huff_decode(&dst[11..15]));
1080        assert_eq!(0x80 | 4, dst[15]);
1081
1082        let mut world = dst[16..17].to_owned();
1083
1084        dst.clear();
1085
1086        assert!(continuation
1087            .encode(&mut (&mut dst).limit(frame::HEADER_LEN + 16))
1088            .is_none());
1089
1090        world.extend_from_slice(&dst[9..12]);
1091        assert_eq!("world", huff_decode(&world));
1092
1093        assert_eq!(24, dst.len());
1094        assert_eq!([0, 0, 15, 9, 4, 0, 0, 0, 0], &dst[0..9]);
1095
1096        // // Next is not indexed
1097        assert_eq!(&[15, 47, 0x80 | 3], &dst[12..15]);
1098        assert_eq!("zomg", huff_decode(&dst[15..18]));
1099        assert_eq!(&[15, 47, 0x80 | 3], &dst[18..21]);
1100        assert_eq!("sup", huff_decode(&dst[21..]));
1101    }
1102
1103    fn huff_decode(src: &[u8]) -> BytesMut {
1104        let mut buf = BytesMut::new();
1105        huffman::decode(src, &mut buf).unwrap()
1106    }
1107
1108    #[test]
1109    fn test_connect_request_pseudo_headers_omits_path_and_scheme() {
1110        // CONNECT requests MUST NOT include :scheme & :path pseudo-header fields
1111        // See: https://datatracker.ietf.org/doc/html/rfc9113#section-8.5
1112
1113        assert_eq!(
1114            Pseudo::request(
1115                Method::CONNECT,
1116                Uri::from_static("https://example.com:8443"),
1117                None
1118            ),
1119            Pseudo {
1120                method: Method::CONNECT.into(),
1121                authority: BytesStr::from_static("example.com:8443").into(),
1122                ..Default::default()
1123            }
1124        );
1125
1126        assert_eq!(
1127            Pseudo::request(
1128                Method::CONNECT,
1129                Uri::from_static("https://example.com/test"),
1130                None
1131            ),
1132            Pseudo {
1133                method: Method::CONNECT.into(),
1134                authority: BytesStr::from_static("example.com").into(),
1135                ..Default::default()
1136            }
1137        );
1138
1139        assert_eq!(
1140            Pseudo::request(Method::CONNECT, Uri::from_static("example.com:8443"), None),
1141            Pseudo {
1142                method: Method::CONNECT.into(),
1143                authority: BytesStr::from_static("example.com:8443").into(),
1144                ..Default::default()
1145            }
1146        );
1147    }
1148
1149    #[test]
1150    fn test_extended_connect_request_pseudo_headers_includes_path_and_scheme() {
1151        // On requests that contain the :protocol pseudo-header field, the
1152        // :scheme and :path pseudo-header fields of the target URI (see
1153        // Section 5) MUST also be included.
1154        // See: https://datatracker.ietf.org/doc/html/rfc8441#section-4
1155
1156        assert_eq!(
1157            Pseudo::request(
1158                Method::CONNECT,
1159                Uri::from_static("https://example.com:8443"),
1160                Protocol::from_static("the-bread-protocol").into()
1161            ),
1162            Pseudo {
1163                method: Method::CONNECT.into(),
1164                authority: BytesStr::from_static("example.com:8443").into(),
1165                scheme: BytesStr::from_static("https").into(),
1166                path: BytesStr::from_static("/").into(),
1167                protocol: Protocol::from_static("the-bread-protocol").into(),
1168                ..Default::default()
1169            }
1170        );
1171
1172        assert_eq!(
1173            Pseudo::request(
1174                Method::CONNECT,
1175                Uri::from_static("https://example.com:8443/test"),
1176                Protocol::from_static("the-bread-protocol").into()
1177            ),
1178            Pseudo {
1179                method: Method::CONNECT.into(),
1180                authority: BytesStr::from_static("example.com:8443").into(),
1181                scheme: BytesStr::from_static("https").into(),
1182                path: BytesStr::from_static("/test").into(),
1183                protocol: Protocol::from_static("the-bread-protocol").into(),
1184                ..Default::default()
1185            }
1186        );
1187
1188        assert_eq!(
1189            Pseudo::request(
1190                Method::CONNECT,
1191                Uri::from_static("http://example.com/a/b/c"),
1192                Protocol::from_static("the-bread-protocol").into()
1193            ),
1194            Pseudo {
1195                method: Method::CONNECT.into(),
1196                authority: BytesStr::from_static("example.com").into(),
1197                scheme: BytesStr::from_static("http").into(),
1198                path: BytesStr::from_static("/a/b/c").into(),
1199                protocol: Protocol::from_static("the-bread-protocol").into(),
1200                ..Default::default()
1201            }
1202        );
1203    }
1204
1205    #[test]
1206    fn test_options_request_with_empty_path_has_asterisk_as_pseudo_path() {
1207        // an OPTIONS request for an "http" or "https" URI that does not include a path component;
1208        // these MUST include a ":path" pseudo-header field with a value of '*' (see Section 7.1 of [HTTP]).
1209        // See: https://datatracker.ietf.org/doc/html/rfc9113#section-8.3.1
1210        assert_eq!(
1211            Pseudo::request(Method::OPTIONS, Uri::from_static("example.com:8080"), None,),
1212            Pseudo {
1213                method: Method::OPTIONS.into(),
1214                authority: BytesStr::from_static("example.com:8080").into(),
1215                path: BytesStr::from_static("*").into(),
1216                ..Default::default()
1217            }
1218        );
1219    }
1220
1221    #[test]
1222    fn test_try_append_prevents_panic_on_max_size_reached() {
1223        // Verify that decoding >24,577 unique headers sets `is_over_size`
1224        // instead of panicking via HeaderMap::append().
1225        //
1226        // HeaderMap::MAX_SIZE = 32,768. With 75% load factor, max entries = 24,576.
1227        // try_append returns Err(MaxSizeReached) at entry 24,577.
1228        // Before the fix (using append), this panicked.
1229        //
1230        // We manually construct HPACK bytes for 25,000 unique headers because
1231        // creating a HeaderMap with that many entries also panics on construction.
1232
1233        // Build HPACK-encoded block:
1234        // Pseudo-headers (indexed refs to static table):
1235        //   :method GET         → 0x82 (static index 2)
1236        //   :scheme http        → 0x86 (static index 6)
1237        //   :path /             → 0x84 (static index 4)
1238        //   :authority "localhost" → literal with indexing (name index 0)
1239        //
1240        // Then 25,000 unique headers: "literal without indexing, new name"
1241        //   0x00 → literal without indexing, name index 0
1242        //   <name_len> <name_bytes>
1243        //   <value_len> <value_bytes>
1244
1245        let num_headers = 25_000;
1246
1247        // Build the HPACK block
1248        let mut hpack = Vec::new();
1249
1250        // Pseudo-headers
1251        hpack.push(0x82u8); // :method GET (static index 2)
1252        hpack.push(0x86); // :scheme http (static index 6)
1253        hpack.push(0x84); // :path / (static index 4)
1254
1255        // :authority "localhost" — literal with incremental indexing
1256        hpack.push(0x41); // literal with indexing, name index 1 (= ":authority")
1257        hpack.push(0x09); // value length 9
1258        hpack.extend_from_slice(b"localhost");
1259
1260        // 25,000 unique headers: "literal without indexing, new name"
1261        // Format: 0x00 + name_len + name + value_len + value
1262        for i in 0..num_headers {
1263            let name = format!("x-h-{i}");
1264            hpack.push(0x00u8); // literal without indexing, name index 0
1265            hpack.push(name.len() as u8);
1266            hpack.extend_from_slice(name.as_bytes());
1267            hpack.push(1u8); // value length 1
1268            hpack.push(b'v');
1269        }
1270
1271        // Build the HTTP/2 HEADERS frame: 9-byte header + HPACK payload
1272        let payload_len = hpack.len();
1273        let mut frame = BytesMut::with_capacity(9 + payload_len);
1274
1275        // Frame header: 3 bytes length, 1 byte type (0x01=HEADERS), 1 byte flags, 4 bytes stream_id
1276        frame.put_u8(((payload_len >> 16) & 0xFF) as u8);
1277        frame.put_u8(((payload_len >> 8) & 0xFF) as u8);
1278        frame.put_u8((payload_len & 0xFF) as u8);
1279        frame.put_u8(0x01); // type: HEADERS
1280        frame.put_u8(0x04); // flags: END_HEADERS
1281        frame.put_u32(1); // stream_id: 1
1282
1283        frame.extend_from_slice(&hpack);
1284
1285        // Parse the HEADERS frame
1286        let head = Head::parse(&frame[..9]);
1287        let payload = BytesMut::from(&frame[9..]);
1288        let (mut headers, mut hpack_data) = Headers::load(head, payload).unwrap();
1289        // hpack_data contains the HPACK payload (no padding/priority in our frame)
1290
1291        // Decode the HPACK block — this should NOT panic
1292        let mut decoder = hpack::Decoder::new(4096);
1293        const DEFAULT_MAX_HEADER_LIST_SIZE: usize = 16 << 20; // 16 MB
1294        headers
1295            .load_hpack(&mut hpack_data, DEFAULT_MAX_HEADER_LIST_SIZE, &mut decoder)
1296            .expect("load_hpack should return Ok");
1297
1298        // Verify that is_over_size was set (try_append returned Err)
1299        assert!(
1300            headers.is_over_size(),
1301            "is_over_size should be true when HeaderMap capacity is exceeded"
1302        );
1303    }
1304
1305    #[test]
1306    fn test_non_option_and_non_connect_requests_include_path_and_scheme() {
1307        let methods = [
1308            Method::GET,
1309            Method::POST,
1310            Method::PUT,
1311            Method::DELETE,
1312            Method::HEAD,
1313            Method::PATCH,
1314            Method::TRACE,
1315        ];
1316
1317        for method in methods {
1318            assert_eq!(
1319                Pseudo::request(
1320                    method.clone(),
1321                    Uri::from_static("http://example.com:8080"),
1322                    None,
1323                ),
1324                Pseudo {
1325                    method: method.clone().into(),
1326                    authority: BytesStr::from_static("example.com:8080").into(),
1327                    scheme: BytesStr::from_static("http").into(),
1328                    path: BytesStr::from_static("/").into(),
1329                    ..Default::default()
1330                }
1331            );
1332            assert_eq!(
1333                Pseudo::request(
1334                    method.clone(),
1335                    Uri::from_static("https://example.com/a/b/c"),
1336                    None,
1337                ),
1338                Pseudo {
1339                    method: method.into(),
1340                    authority: BytesStr::from_static("example.com").into(),
1341                    scheme: BytesStr::from_static("https").into(),
1342                    path: BytesStr::from_static("/a/b/c").into(),
1343                    ..Default::default()
1344                }
1345            );
1346        }
1347    }
1348}