Coverage Report

Created: 2026-10-28 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2/src/frame/headers.rs
Line
Count
Source
1
use super::{util, StreamDependency, StreamId};
2
use crate::ext::Protocol;
3
use crate::frame::{Error, Frame, Head, Kind};
4
use crate::hpack::{self, BytesStr};
5
6
use http::header::{self, HeaderName, HeaderValue};
7
use http::{uri, HeaderMap, Method, Request, StatusCode, Uri};
8
9
use bytes::{Buf, BufMut, BytesMut};
10
11
use std::fmt;
12
use std::io::Cursor;
13
use std::ops::ControlFlow;
14
15
type EncodeBuf<'a> = bytes::buf::Limit<&'a mut BytesMut>;
16
17
const 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)]
23
pub 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)]
38
pub struct HeadersFlag(u8);
39
40
#[derive(Eq, PartialEq)]
41
pub 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)]
56
pub struct PushPromiseFlag(u8);
57
58
#[derive(Debug)]
59
pub 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)]
68
pub 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)]
81
pub 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)]
90
struct 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)]
106
struct EncodingHeaderBlock {
107
    hpack: BytesMut,
108
}
109
110
const END_STREAM: u8 = 0x1;
111
const END_HEADERS: u8 = 0x4;
112
const PADDED: u8 = 0x8;
113
const PRIORITY: u8 = 0x20;
114
const ALL: u8 = END_STREAM | END_HEADERS | PADDED | PRIORITY;
115
116
// ===== impl Headers =====
117
118
impl Headers {
119
    /// Create a new HEADERS frame
120
400k
    pub fn new(stream_id: StreamId, pseudo: Pseudo, fields: HeaderMap) -> Self {
121
400k
        Headers {
122
400k
            stream_id,
123
400k
            stream_dep: None,
124
400k
            header_block: HeaderBlock {
125
400k
                field_size: calculate_headermap_size(&fields),
126
400k
                fields,
127
400k
                is_over_size: false,
128
400k
                pseudo,
129
400k
            },
130
400k
            flags: HeadersFlag::default(),
131
400k
        }
132
400k
    }
133
134
0
    pub fn trailers(stream_id: StreamId, fields: HeaderMap) -> Self {
135
0
        let mut flags = HeadersFlag::default();
136
0
        flags.set_end_stream();
137
138
0
        Headers {
139
0
            stream_id,
140
0
            stream_dep: None,
141
0
            header_block: HeaderBlock {
142
0
                field_size: calculate_headermap_size(&fields),
143
0
                fields,
144
0
                is_over_size: false,
145
0
                pseudo: Pseudo::default(),
146
0
            },
147
0
            flags,
148
0
        }
149
0
    }
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
40.6k
    pub fn load(head: Head, mut src: BytesMut) -> Result<(Self, BytesMut), Error> {
155
40.6k
        let flags = HeadersFlag(head.flag());
156
40.6k
        let mut pad = 0;
157
158
40.6k
        tracing::trace!("loading headers; flags={:?}", flags);
159
160
40.6k
        if head.stream_id().is_zero() {
161
3
            return Err(Error::InvalidStreamId);
162
40.6k
        }
163
164
        // Read the padding length
165
40.6k
        if flags.is_padded() {
166
2.76k
            if src.is_empty() {
167
3
                return Err(Error::MalformedMessage);
168
2.75k
            }
169
2.75k
            pad = src[0] as usize;
170
171
            // Drop the padding
172
2.75k
            src.advance(1);
173
37.9k
        }
174
175
        // Read the stream dependency
176
40.6k
        let stream_dep = if flags.is_priority() {
177
5.82k
            if src.len() < 5 {
178
1
                return Err(Error::MalformedMessage);
179
5.82k
            }
180
5.82k
            let stream_dep = StreamDependency::load(&src[..5])?;
181
182
5.82k
            if stream_dep.dependency_id() == head.stream_id() {
183
69
                return Err(Error::InvalidDependencyId);
184
5.75k
            }
185
186
            // Drop the next 5 bytes
187
5.75k
            src.advance(5);
188
189
5.75k
            Some(stream_dep)
190
        } else {
191
34.8k
            None
192
        };
193
194
40.6k
        if pad > 0 {
195
2.67k
            if pad > src.len() {
196
14
                return Err(Error::TooMuchPadding);
197
2.66k
            }
198
199
2.66k
            let len = src.len() - pad;
200
2.66k
            src.truncate(len);
201
37.9k
        }
202
203
40.6k
        let headers = Headers {
204
40.6k
            stream_id: head.stream_id(),
205
40.6k
            stream_dep,
206
40.6k
            header_block: HeaderBlock {
207
40.6k
                fields: HeaderMap::new(),
208
40.6k
                field_size: 0,
209
40.6k
                is_over_size: false,
210
40.6k
                pseudo: Pseudo::default(),
211
40.6k
            },
212
40.6k
            flags,
213
40.6k
        };
214
215
40.6k
        Ok((headers, src))
216
40.6k
    }
217
218
51.0k
    pub fn load_hpack(
219
51.0k
        &mut self,
220
51.0k
        src: &mut BytesMut,
221
51.0k
        max_header_list_size: usize,
222
51.0k
        decoder: &mut hpack::Decoder,
223
51.0k
    ) -> Result<(), Error> {
224
51.0k
        self.header_block.load(src, max_header_list_size, decoder)
225
51.0k
    }
226
227
418k
    pub fn stream_id(&self) -> StreamId {
228
418k
        self.stream_id
229
418k
    }
230
231
40.6k
    pub fn is_end_headers(&self) -> bool {
232
40.6k
        self.flags.is_end_headers()
233
40.6k
    }
234
235
145
    pub fn set_end_headers(&mut self) {
236
145
        self.flags.set_end_headers();
237
145
    }
238
239
402k
    pub fn is_end_stream(&self) -> bool {
240
402k
        self.flags.is_end_stream()
241
402k
    }
242
243
741
    pub fn set_end_stream(&mut self) {
244
741
        self.flags.set_end_stream()
245
741
    }
246
247
10.1k
    pub fn is_over_size(&self) -> bool {
248
10.1k
        self.header_block.is_over_size
249
10.1k
    }
250
251
1.42k
    pub fn into_parts(self) -> (Pseudo, HeaderMap) {
252
1.42k
        (self.header_block.pseudo, self.header_block.fields)
253
1.42k
    }
254
255
    #[cfg(feature = "unstable")]
256
0
    pub fn pseudo_mut(&mut self) -> &mut Pseudo {
257
0
        &mut self.header_block.pseudo
258
0
    }
259
260
26
    pub(crate) fn pseudo(&self) -> &Pseudo {
261
26
        &self.header_block.pseudo
262
26
    }
263
264
    /// Whether it has status 1xx
265
1.30k
    pub(crate) fn is_informational(&self) -> bool {
266
1.30k
        self.header_block.pseudo.is_informational()
267
1.30k
    }
268
269
401k
    pub fn fields(&self) -> &HeaderMap {
270
401k
        &self.header_block.fields
271
401k
    }
272
273
13
    pub fn into_fields(self) -> HeaderMap {
274
13
        self.header_block.fields
275
13
    }
276
277
218k
    pub fn encode(
278
218k
        self,
279
218k
        encoder: &mut hpack::Encoder,
280
218k
        dst: &mut EncodeBuf<'_>,
281
218k
    ) -> Option<Continuation> {
282
        // At this point, the `is_end_headers` flag should always be set
283
218k
        debug_assert!(self.flags.is_end_headers());
284
285
        // Get the HEADERS frame head
286
218k
        let head = self.head();
287
288
218k
        self.header_block
289
218k
            .into_encoding(encoder)
290
218k
            .encode(&head, dst, Some(encoder), |_| {})
291
218k
    }
292
293
218k
    fn head(&self) -> Head {
294
218k
        Head::new(Kind::Headers, self.flags.into(), self.stream_id)
295
218k
    }
296
}
297
298
impl<T> From<Headers> for Frame<T> {
299
625k
    fn from(src: Headers) -> Self {
300
625k
        Frame::Headers(src)
301
625k
    }
<h2::frame::Frame as core::convert::From<h2::frame::headers::Headers>>::from
Line
Count
Source
299
407k
    fn from(src: Headers) -> Self {
300
407k
        Frame::Headers(src)
301
407k
    }
<h2::frame::Frame<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as core::convert::From<h2::frame::headers::Headers>>::from
Line
Count
Source
299
218k
    fn from(src: Headers) -> Self {
300
218k
        Frame::Headers(src)
301
218k
    }
302
}
303
304
impl fmt::Debug for Headers {
305
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306
0
        let mut builder = f.debug_struct("Headers");
307
0
        builder
308
0
            .field("stream_id", &self.stream_id)
309
0
            .field("flags", &self.flags);
310
311
0
        if let Some(ref protocol) = self.header_block.pseudo.protocol {
312
0
            builder.field("protocol", protocol);
313
0
        }
314
315
0
        if let Some(ref dep) = self.stream_dep {
316
0
            builder.field("stream_dep", dep);
317
0
        }
318
319
        // `fields` and `pseudo` purposefully not included
320
0
        builder.finish()
321
0
    }
322
}
323
324
// ===== util =====
325
326
#[derive(Debug, PartialEq, Eq)]
327
pub struct ParseU64Error;
328
329
413
pub fn parse_u64(src: &[u8]) -> Result<u64, ParseU64Error> {
330
413
    if src.len() > 19 {
331
        // At danger for overflow...
332
2
        return Err(ParseU64Error);
333
411
    }
334
335
411
    let mut ret = 0;
336
337
1.08k
    for &d in src {
338
712
        if d < b'0' || d > b'9' {
339
41
            return Err(ParseU64Error);
340
671
        }
341
342
671
        ret *= 10;
343
671
        ret += (d - b'0') as u64;
344
    }
345
346
370
    Ok(ret)
347
413
}
348
349
// ===== impl PushPromise =====
350
351
#[derive(Debug)]
352
pub enum PushPromiseHeaderError {
353
    InvalidContentLength(Result<u64, ParseU64Error>),
354
    NotSafeAndCacheable,
355
}
356
357
impl PushPromise {
358
0
    pub fn new(
359
0
        stream_id: StreamId,
360
0
        promised_id: StreamId,
361
0
        pseudo: Pseudo,
362
0
        fields: HeaderMap,
363
0
    ) -> Self {
364
0
        PushPromise {
365
0
            flags: PushPromiseFlag::default(),
366
0
            header_block: HeaderBlock {
367
0
                field_size: calculate_headermap_size(&fields),
368
0
                fields,
369
0
                is_over_size: false,
370
0
                pseudo,
371
0
            },
372
0
            promised_id,
373
0
            stream_id,
374
0
        }
375
0
    }
376
377
274
    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
274
        for content_length in req.headers().get_all(header::CONTENT_LENGTH) {
385
166
            let parsed_length = parse_u64(content_length.as_bytes());
386
166
            if parsed_length != Ok(0) {
387
18
                return Err(InvalidContentLength(parsed_length));
388
148
            }
389
        }
390
        // "The server MUST include a method in the :method pseudo-header field
391
        // that is safe and cacheable"
392
256
        if !Self::safe_and_cacheable(req.method()) {
393
60
            return Err(NotSafeAndCacheable);
394
196
        }
395
396
196
        Ok(())
397
274
    }
398
399
256
    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
256
        method == Method::GET || method == Method::HEAD
403
256
    }
404
405
0
    pub fn fields(&self) -> &HeaderMap {
406
0
        &self.header_block.fields
407
0
    }
408
409
    #[cfg(feature = "unstable")]
410
0
    pub fn into_fields(self) -> HeaderMap {
411
0
        self.header_block.fields
412
0
    }
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
2.52k
    pub fn load(head: Head, mut src: BytesMut) -> Result<(Self, BytesMut), Error> {
418
2.52k
        let flags = PushPromiseFlag(head.flag());
419
2.52k
        let mut pad = 0;
420
421
2.52k
        if head.stream_id().is_zero() {
422
2
            return Err(Error::InvalidStreamId);
423
2.52k
        }
424
425
        // Read the padding length
426
2.52k
        if flags.is_padded() {
427
122
            if src.is_empty() {
428
10
                return Err(Error::MalformedMessage);
429
112
            }
430
431
            // TODO: Ensure payload is sized correctly
432
112
            pad = src[0] as usize;
433
434
            // Drop the padding
435
112
            src.advance(1);
436
2.40k
        }
437
438
2.51k
        if src.len() < 5 {
439
23
            return Err(Error::MalformedMessage);
440
2.49k
        }
441
442
2.49k
        let (promised_id, _) = StreamId::parse(&src[..4]);
443
        // Drop promised_id bytes
444
2.49k
        src.advance(4);
445
446
2.49k
        if pad > 0 {
447
94
            if pad > src.len() {
448
9
                return Err(Error::TooMuchPadding);
449
85
            }
450
451
85
            let len = src.len() - pad;
452
85
            src.truncate(len);
453
2.39k
        }
454
455
2.48k
        let frame = PushPromise {
456
2.48k
            flags,
457
2.48k
            header_block: HeaderBlock {
458
2.48k
                fields: HeaderMap::new(),
459
2.48k
                field_size: 0,
460
2.48k
                is_over_size: false,
461
2.48k
                pseudo: Pseudo::default(),
462
2.48k
            },
463
2.48k
            promised_id,
464
2.48k
            stream_id: head.stream_id(),
465
2.48k
        };
466
2.48k
        Ok((frame, src))
467
2.52k
    }
468
469
2.48k
    pub fn load_hpack(
470
2.48k
        &mut self,
471
2.48k
        src: &mut BytesMut,
472
2.48k
        max_header_list_size: usize,
473
2.48k
        decoder: &mut hpack::Decoder,
474
2.48k
    ) -> Result<(), Error> {
475
2.48k
        self.header_block.load(src, max_header_list_size, decoder)
476
2.48k
    }
477
478
1.05k
    pub fn stream_id(&self) -> StreamId {
479
1.05k
        self.stream_id
480
1.05k
    }
481
482
1.98k
    pub fn promised_id(&self) -> StreamId {
483
1.98k
        self.promised_id
484
1.98k
    }
485
486
2.48k
    pub fn is_end_headers(&self) -> bool {
487
2.48k
        self.flags.is_end_headers()
488
2.48k
    }
489
490
0
    pub fn set_end_headers(&mut self) {
491
0
        self.flags.set_end_headers();
492
0
    }
493
494
931
    pub fn is_over_size(&self) -> bool {
495
931
        self.header_block.is_over_size
496
931
    }
497
498
0
    pub fn encode(
499
0
        self,
500
0
        encoder: &mut hpack::Encoder,
501
0
        dst: &mut EncodeBuf<'_>,
502
0
    ) -> Option<Continuation> {
503
        // At this point, the `is_end_headers` flag should always be set
504
0
        debug_assert!(self.flags.is_end_headers());
505
506
0
        let head = self.head();
507
0
        let promised_id = self.promised_id;
508
509
0
        self.header_block
510
0
            .into_encoding(encoder)
511
0
            .encode(&head, dst, Some(encoder), |dst| {
512
0
                dst.put_u32(promised_id.into());
513
0
            })
514
0
    }
515
516
0
    fn head(&self) -> Head {
517
0
        Head::new(Kind::PushPromise, self.flags.into(), self.stream_id)
518
0
    }
519
520
    /// Consume `self`, returning the parts of the frame
521
931
    pub fn into_parts(self) -> (Pseudo, HeaderMap) {
522
931
        (self.header_block.pseudo, self.header_block.fields)
523
931
    }
524
}
525
526
impl<T> From<PushPromise> for Frame<T> {
527
1.05k
    fn from(src: PushPromise) -> Self {
528
1.05k
        Frame::PushPromise(src)
529
1.05k
    }
<h2::frame::Frame as core::convert::From<h2::frame::headers::PushPromise>>::from
Line
Count
Source
527
1.05k
    fn from(src: PushPromise) -> Self {
528
1.05k
        Frame::PushPromise(src)
529
1.05k
    }
Unexecuted instantiation: <h2::frame::Frame<h2::proto::streams::prioritize::Prioritized<bytes::bytes::Bytes>> as core::convert::From<h2::frame::headers::PushPromise>>::from
530
}
531
532
impl fmt::Debug for PushPromise {
533
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534
0
        f.debug_struct("PushPromise")
535
0
            .field("stream_id", &self.stream_id)
536
0
            .field("promised_id", &self.promised_id)
537
0
            .field("flags", &self.flags)
538
            // `fields` and `pseudo` purposefully not included
539
0
            .finish()
540
0
    }
541
}
542
543
// ===== impl Continuation =====
544
545
impl Continuation {
546
0
    fn head(&self) -> Head {
547
0
        Head::new(Kind::Continuation, END_HEADERS, self.stream_id)
548
0
    }
549
550
0
    pub fn encode(self, dst: &mut EncodeBuf<'_>) -> Option<Continuation> {
551
        // Get the CONTINUATION frame head
552
0
        let head = self.head();
553
554
0
        self.header_block.encode(&head, dst, None, |_| {})
555
0
    }
556
}
557
558
// ===== impl Pseudo =====
559
560
impl Pseudo {
561
400k
    pub fn request(method: Method, uri: Uri, protocol: Option<Protocol>) -> Self {
562
400k
        let parts = uri::Parts::from(uri);
563
564
400k
        let (scheme, path) = if method == Method::CONNECT && protocol.is_none() {
565
0
            (None, None)
566
        } else {
567
400k
            let path = parts
568
400k
                .path_and_query
569
400k
                .map(|v| BytesStr::from(v.as_str()))
570
400k
                .unwrap_or(BytesStr::from_static(""));
571
572
400k
            let path = if !path.is_empty() {
573
399k
                path
574
583
            } else if method == Method::OPTIONS {
575
0
                BytesStr::from_static("*")
576
            } else {
577
583
                BytesStr::from_static("/")
578
            };
579
580
400k
            (parts.scheme, Some(path))
581
        };
582
583
400k
        let mut pseudo = Pseudo {
584
400k
            method: Some(method),
585
400k
            scheme: None,
586
400k
            authority: None,
587
400k
            path,
588
400k
            protocol,
589
400k
            status: None,
590
400k
        };
591
592
        // If the URI includes a scheme component, add it to the pseudo headers
593
400k
        if let Some(scheme) = scheme {
594
399k
            pseudo.set_scheme(scheme);
595
399k
        }
596
597
        // If the URI includes an authority component, add it to the pseudo
598
        // headers
599
400k
        if let Some(authority) = parts.authority {
600
400k
            pseudo.set_authority(BytesStr::from(authority.as_str()));
601
400k
        }
602
603
400k
        pseudo
604
400k
    }
605
606
0
    pub fn response(status: StatusCode) -> Self {
607
0
        Pseudo {
608
0
            method: None,
609
0
            scheme: None,
610
0
            authority: None,
611
0
            path: None,
612
0
            protocol: None,
613
0
            status: Some(status),
614
0
        }
615
0
    }
616
617
    #[cfg(feature = "unstable")]
618
0
    pub fn set_status(&mut self, value: StatusCode) {
619
0
        self.status = Some(value);
620
0
    }
621
622
399k
    pub fn set_scheme(&mut self, scheme: uri::Scheme) {
623
399k
        let bytes_str = match scheme.as_str() {
624
399k
            "http" => BytesStr::from_static("http"),
625
399k
            "https" => BytesStr::from_static("https"),
626
48
            s => BytesStr::from(s),
627
        };
628
399k
        self.scheme = Some(bytes_str);
629
399k
    }
630
631
    #[cfg(feature = "unstable")]
632
0
    pub fn set_protocol(&mut self, protocol: Protocol) {
633
0
        self.protocol = Some(protocol);
634
0
    }
635
636
400k
    pub fn set_authority(&mut self, authority: BytesStr) {
637
400k
        self.authority = Some(authority);
638
400k
    }
639
640
    /// Whether it has status 1xx
641
2.72k
    pub(crate) fn is_informational(&self) -> bool {
642
2.72k
        self.status
643
2.72k
            .map_or(false, |status| status.is_informational())
644
2.72k
    }
645
}
646
647
// ===== impl EncodingHeaderBlock =====
648
649
impl EncodingHeaderBlock {
650
218k
    fn encode<F>(
651
218k
        mut self,
652
218k
        head: &Head,
653
218k
        dst: &mut EncodeBuf<'_>,
654
218k
        encoder: Option<&mut hpack::Encoder>,
655
218k
        f: F,
656
218k
    ) -> Option<Continuation>
657
218k
    where
658
218k
        F: FnOnce(&mut EncodeBuf<'_>),
659
    {
660
218k
        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
218k
        head.encode(0, dst);
666
667
218k
        let payload_pos = dst.get_ref().len();
668
669
218k
        f(dst);
670
671
        // Now, encode the header payload
672
218k
        let continuation = if self.hpack.len() > dst.remaining_mut() {
673
0
            let head_part = self.hpack.split_to(dst.remaining_mut());
674
0
            dst.put_slice(&head_part);
675
676
0
            Some(Continuation {
677
0
                stream_id: head.stream_id(),
678
0
                header_block: self,
679
0
            })
680
        } else {
681
218k
            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
218k
            if let Some(encoder) = encoder {
685
218k
                encoder.return_scratch(self.hpack);
686
218k
            }
687
688
218k
            None
689
        };
690
691
        // Compute the header block length
692
218k
        let payload_len = (dst.get_ref().len() - payload_pos) as u64;
693
694
        // Write the frame length
695
218k
        let payload_len_be = payload_len.to_be_bytes();
696
1.09M
        assert!(payload_len_be[0..5].iter().all(|b| *b == 0));
<h2::frame::headers::EncodingHeaderBlock>::encode::<<h2::frame::headers::Headers>::encode::{closure#0}>::{closure#0}
Line
Count
Source
696
1.09M
        assert!(payload_len_be[0..5].iter().all(|b| *b == 0));
Unexecuted instantiation: <h2::frame::headers::EncodingHeaderBlock>::encode::<<h2::frame::headers::PushPromise>::encode::{closure#0}>::{closure#0}
Unexecuted instantiation: <h2::frame::headers::EncodingHeaderBlock>::encode::<<h2::frame::headers::Continuation>::encode::{closure#0}>::{closure#0}
697
218k
        (dst.get_mut()[head_pos..head_pos + 3]).copy_from_slice(&payload_len_be[5..]);
698
699
218k
        if continuation.is_some() {
700
            // There will be continuation frames, so the `is_end_headers` flag
701
            // must be unset
702
0
            debug_assert!(dst.get_ref()[head_pos + 4] & END_HEADERS == END_HEADERS);
703
704
0
            dst.get_mut()[head_pos + 4] -= END_HEADERS;
705
218k
        }
706
707
218k
        continuation
708
218k
    }
<h2::frame::headers::EncodingHeaderBlock>::encode::<<h2::frame::headers::Headers>::encode::{closure#0}>
Line
Count
Source
650
218k
    fn encode<F>(
651
218k
        mut self,
652
218k
        head: &Head,
653
218k
        dst: &mut EncodeBuf<'_>,
654
218k
        encoder: Option<&mut hpack::Encoder>,
655
218k
        f: F,
656
218k
    ) -> Option<Continuation>
657
218k
    where
658
218k
        F: FnOnce(&mut EncodeBuf<'_>),
659
    {
660
218k
        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
218k
        head.encode(0, dst);
666
667
218k
        let payload_pos = dst.get_ref().len();
668
669
218k
        f(dst);
670
671
        // Now, encode the header payload
672
218k
        let continuation = if self.hpack.len() > dst.remaining_mut() {
673
0
            let head_part = self.hpack.split_to(dst.remaining_mut());
674
0
            dst.put_slice(&head_part);
675
676
0
            Some(Continuation {
677
0
                stream_id: head.stream_id(),
678
0
                header_block: self,
679
0
            })
680
        } else {
681
218k
            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
218k
            if let Some(encoder) = encoder {
685
218k
                encoder.return_scratch(self.hpack);
686
218k
            }
687
688
218k
            None
689
        };
690
691
        // Compute the header block length
692
218k
        let payload_len = (dst.get_ref().len() - payload_pos) as u64;
693
694
        // Write the frame length
695
218k
        let payload_len_be = payload_len.to_be_bytes();
696
218k
        assert!(payload_len_be[0..5].iter().all(|b| *b == 0));
697
218k
        (dst.get_mut()[head_pos..head_pos + 3]).copy_from_slice(&payload_len_be[5..]);
698
699
218k
        if continuation.is_some() {
700
            // There will be continuation frames, so the `is_end_headers` flag
701
            // must be unset
702
0
            debug_assert!(dst.get_ref()[head_pos + 4] & END_HEADERS == END_HEADERS);
703
704
0
            dst.get_mut()[head_pos + 4] -= END_HEADERS;
705
218k
        }
706
707
218k
        continuation
708
218k
    }
Unexecuted instantiation: <h2::frame::headers::EncodingHeaderBlock>::encode::<<h2::frame::headers::PushPromise>::encode::{closure#0}>
Unexecuted instantiation: <h2::frame::headers::EncodingHeaderBlock>::encode::<<h2::frame::headers::Continuation>::encode::{closure#0}>
709
}
710
711
// ===== impl Iter =====
712
713
impl Iterator for Iter {
714
    type Item = hpack::Header<Option<HeaderName>>;
715
716
1.09M
    fn next(&mut self) -> Option<Self::Item> {
717
        use crate::hpack::Header::*;
718
719
1.09M
        if let Some(ref mut pseudo) = self.pseudo {
720
1.09M
            if let Some(method) = pseudo.method.take() {
721
218k
                return Some(Method(method));
722
874k
            }
723
724
874k
            if let Some(scheme) = pseudo.scheme.take() {
725
218k
                return Some(Scheme(scheme));
726
655k
            }
727
728
655k
            if let Some(authority) = pseudo.authority.take() {
729
218k
                return Some(Authority(authority));
730
437k
            }
731
732
437k
            if let Some(path) = pseudo.path.take() {
733
218k
                return Some(Path(path));
734
218k
            }
735
736
218k
            if let Some(protocol) = pseudo.protocol.take() {
737
0
                return Some(Protocol(protocol));
738
218k
            }
739
740
218k
            if let Some(status) = pseudo.status.take() {
741
0
                return Some(Status(status));
742
218k
            }
743
0
        }
744
745
218k
        self.pseudo = None;
746
747
218k
        self.fields
748
218k
            .next()
749
218k
            .map(|(name, value)| Field { name, value })
750
1.09M
    }
751
}
752
753
// ===== impl HeadersFlag =====
754
755
impl HeadersFlag {
756
0
    pub fn empty() -> HeadersFlag {
757
0
        HeadersFlag(0)
758
0
    }
759
760
0
    pub fn load(bits: u8) -> HeadersFlag {
761
0
        HeadersFlag(bits & ALL)
762
0
    }
763
764
402k
    pub fn is_end_stream(&self) -> bool {
765
402k
        self.0 & END_STREAM == END_STREAM
766
402k
    }
767
768
741
    pub fn set_end_stream(&mut self) {
769
741
        self.0 |= END_STREAM;
770
741
    }
771
772
40.6k
    pub fn is_end_headers(&self) -> bool {
773
40.6k
        self.0 & END_HEADERS == END_HEADERS
774
40.6k
    }
775
776
145
    pub fn set_end_headers(&mut self) {
777
145
        self.0 |= END_HEADERS;
778
145
    }
779
780
40.6k
    pub fn is_padded(&self) -> bool {
781
40.6k
        self.0 & PADDED == PADDED
782
40.6k
    }
783
784
40.6k
    pub fn is_priority(&self) -> bool {
785
40.6k
        self.0 & PRIORITY == PRIORITY
786
40.6k
    }
787
}
788
789
impl Default for HeadersFlag {
790
    /// Returns a `HeadersFlag` value with `END_HEADERS` set.
791
400k
    fn default() -> Self {
792
400k
        HeadersFlag(END_HEADERS)
793
400k
    }
794
}
795
796
impl From<HeadersFlag> for u8 {
797
218k
    fn from(src: HeadersFlag) -> u8 {
798
218k
        src.0
799
218k
    }
800
}
801
802
impl fmt::Debug for HeadersFlag {
803
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
804
0
        util::debug_flags(fmt, self.0)
805
0
            .flag_if(self.is_end_headers(), "END_HEADERS")
806
0
            .flag_if(self.is_end_stream(), "END_STREAM")
807
0
            .flag_if(self.is_padded(), "PADDED")
808
0
            .flag_if(self.is_priority(), "PRIORITY")
809
0
            .finish()
810
0
    }
811
}
812
813
// ===== impl PushPromiseFlag =====
814
815
impl PushPromiseFlag {
816
0
    pub fn empty() -> PushPromiseFlag {
817
0
        PushPromiseFlag(0)
818
0
    }
819
820
0
    pub fn load(bits: u8) -> PushPromiseFlag {
821
0
        PushPromiseFlag(bits & ALL)
822
0
    }
823
824
2.48k
    pub fn is_end_headers(&self) -> bool {
825
2.48k
        self.0 & END_HEADERS == END_HEADERS
826
2.48k
    }
827
828
0
    pub fn set_end_headers(&mut self) {
829
0
        self.0 |= END_HEADERS;
830
0
    }
831
832
2.52k
    pub fn is_padded(&self) -> bool {
833
2.52k
        self.0 & PADDED == PADDED
834
2.52k
    }
835
}
836
837
impl Default for PushPromiseFlag {
838
    /// Returns a `PushPromiseFlag` value with `END_HEADERS` set.
839
0
    fn default() -> Self {
840
0
        PushPromiseFlag(END_HEADERS)
841
0
    }
842
}
843
844
impl From<PushPromiseFlag> for u8 {
845
0
    fn from(src: PushPromiseFlag) -> u8 {
846
0
        src.0
847
0
    }
848
}
849
850
impl fmt::Debug for PushPromiseFlag {
851
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
852
0
        util::debug_flags(fmt, self.0)
853
0
            .flag_if(self.is_end_headers(), "END_HEADERS")
854
0
            .flag_if(self.is_padded(), "PADDED")
855
0
            .finish()
856
0
    }
857
}
858
859
// ===== HeaderBlock =====
860
861
impl HeaderBlock {
862
53.4k
    fn load(
863
53.4k
        &mut self,
864
53.4k
        src: &mut BytesMut,
865
53.4k
        max_header_list_size: usize,
866
53.4k
        decoder: &mut hpack::Decoder,
867
53.4k
    ) -> Result<(), Error> {
868
53.4k
        let mut reg = !self.fields.is_empty();
869
53.4k
        let mut malformed = false;
870
53.4k
        let mut header_list_way_too_large = false;
871
53.4k
        let mut headers_size = self.calculate_header_list_size();
872
53.4k
        let max_header_list_abuse_size =
873
53.4k
            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
53.4k
        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
726k
        let res = decoder.decode(&mut cursor, |header| {
920
            use crate::hpack::Header::*;
921
922
726k
            match header {
923
534k
                Field { name, value } => {
924
                    // Connection level header fields are not supported and must
925
                    // result in a protocol error.
926
927
534k
                    if name == header::CONNECTION
928
533k
                        || name == header::TRANSFER_ENCODING
929
528k
                        || name == header::UPGRADE
930
528k
                        || name == "keep-alive"
931
528k
                        || name == "proxy-connection"
932
                    {
933
6.31k
                        tracing::trace!("load_hpack; connection level header");
934
6.31k
                        malformed = true;
935
528k
                    } else if name == header::TE && value != "trailers" {
936
537
                        tracing::trace!(
937
0
                            "load_hpack; TE header not set to trailers; val={:?}",
938
                            value
939
                        );
940
537
                        malformed = true;
941
                    } else {
942
527k
                        reg = true;
943
944
527k
                        let header_size = decoded_header_size(name.as_str().len(), value.len());
945
527k
                        headers_size += header_size;
946
527k
                        if check_size!().is_break() {
947
0
                            return ControlFlow::Break(());
948
527k
                        }
949
527k
                        if !self.is_over_size {
950
527k
                            self.field_size += header_size;
951
527k
                            if self.fields.try_append(name, value).is_err() {
952
0
                                // HeaderMap capacity exceeded — treat as over-size
953
0
                                // so the stream is rejected downstream (RST_STREAM / 431)
954
0
                                // instead of panicking on the 24,577th unique header.
955
0
                                self.is_over_size = true;
956
527k
                            }
957
0
                        }
958
                    }
959
                }
960
18.5k
                Authority(v) => set_pseudo!(authority, v),
961
47.9k
                Method(v) => set_pseudo!(method, v),
962
24.4k
                Scheme(v) => set_pseudo!(scheme, v),
963
21.8k
                Path(v) => set_pseudo!(path, v),
964
883
                Protocol(v) => set_pseudo!(protocol, v),
965
77.8k
                Status(v) => set_pseudo!(status, v),
966
            }
967
968
726k
            ControlFlow::Continue(())
969
726k
        });
970
971
53.4k
        match res {
972
37.7k
            Ok(()) => {}
973
15.7k
            Err(e) => {
974
15.7k
                tracing::trace!("hpack decoding error; err={:?}", e);
975
15.7k
                return Err(e.into());
976
            }
977
        }
978
979
37.7k
        if header_list_way_too_large {
980
0
            tracing::trace!("header list way too large; aborting connection");
981
0
            return Err(Error::HeaderListWayTooLarge);
982
37.7k
        }
983
984
37.7k
        if malformed {
985
28.0k
            tracing::trace!("malformed message");
986
28.0k
            return Err(Error::MalformedMessage);
987
9.69k
        }
988
989
9.69k
        Ok(())
990
53.4k
    }
991
992
218k
    fn into_encoding(self, encoder: &mut hpack::Encoder) -> EncodingHeaderBlock {
993
218k
        let mut hpack = encoder.take_scratch();
994
218k
        hpack.clear();
995
218k
        let headers = Iter {
996
218k
            pseudo: Some(self.pseudo),
997
218k
            fields: self.fields.into_iter(),
998
218k
        };
999
1000
218k
        encoder.encode(headers, &mut hpack);
1001
1002
218k
        EncodingHeaderBlock { hpack }
1003
218k
    }
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
53.4k
    fn calculate_header_list_size(&self) -> usize {
1013
        macro_rules! pseudo_size {
1014
            ($name:ident) => {{
1015
                self.pseudo
1016
                    .$name
1017
                    .as_ref()
1018
6.99k
                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
<h2::frame::headers::HeaderBlock>::calculate_header_list_size::{closure#0}
Line
Count
Source
1018
1.85k
                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
<h2::frame::headers::HeaderBlock>::calculate_header_list_size::{closure#2}
Line
Count
Source
1018
81
                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
<h2::frame::headers::HeaderBlock>::calculate_header_list_size::{closure#3}
Line
Count
Source
1018
1.99k
                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
<h2::frame::headers::HeaderBlock>::calculate_header_list_size::{closure#4}
Line
Count
Source
1018
2.02k
                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
<h2::frame::headers::HeaderBlock>::calculate_header_list_size::{closure#1}
Line
Count
Source
1018
1.03k
                    .map(|m| decoded_header_size(stringify!($name).len() + 1, m.as_str().len()))
1019
                    .unwrap_or(0)
1020
            }};
1021
        }
1022
1023
53.4k
        pseudo_size!(method)
1024
53.4k
            + pseudo_size!(scheme)
1025
53.4k
            + pseudo_size!(status)
1026
53.4k
            + pseudo_size!(authority)
1027
53.4k
            + pseudo_size!(path)
1028
53.4k
            + self.field_size
1029
53.4k
    }
1030
}
1031
1032
400k
fn calculate_headermap_size(map: &HeaderMap) -> usize {
1033
400k
    map.iter()
1034
400k
        .map(|(name, value)| decoded_header_size(name.as_str().len(), value.len()))
1035
400k
        .sum::<usize>()
1036
400k
}
1037
1038
557k
fn decoded_header_size(name: usize, value: usize) -> usize {
1039
557k
    name + value + 32
1040
557k
}
1041
1042
#[cfg(test)]
1043
mod 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
}