Skip to main content

http_net/
head.rs

1//! Incremental scanning of message heads, their interpretation, and the
2//! borrowed views handed to callers.
3//!
4//! The scanner finds one CRLF-terminated line at a time and remembers where
5//! it stopped searching, so input that arrives one byte at a time is still
6//! examined once: head parsing is linear in the head's length no matter how
7//! it is split. Each line is fully validated when it completes; field
8//! positions are stored as offsets from the message start so the head can be
9//! read back without copying.
10
11use alloc::vec::Vec;
12use core::{fmt, slice};
13
14use crate::{
15    error::HttpError,
16    limits::Limits,
17    method::Method,
18    redact::{FieldName, FieldValue, Target},
19    scan::{
20        ListSplit, check_field_value, find_byte, is_host_value, is_ows, is_reason, is_target_chars,
21        is_tchar, is_token, list_elements, parse_decimal, printable_run, trim_ows,
22    },
23};
24
25/// A byte range of a message head: `start..end`, as offsets into
26/// [`RawHead::bytes`](crate::RawHead::bytes) (or into the input of a
27/// stateless parser).
28///
29/// Offsets are `u32` because the head and trailer budgets in [`Limits`]
30/// are each capped at 16 MiB, so
31/// [`Limits::buffer_capacity`](crate::Limits::buffer_capacity) stays far
32/// below `u32::MAX`; body bytes are counted in `u64` and never indexed.
33/// Spans stay valid when the head
34/// bytes are moved or copied, which is what makes a head cheap to copy into
35/// a passport ([`RequestHead::copy_into`]).
36///
37/// # Examples
38///
39/// ```
40/// use http_net::Span;
41///
42/// let head = b"GET / HTTP/1.1\r\n";
43/// let method = Span { start: 0, end: 3 };
44/// assert_eq!(method.get(head), b"GET");
45/// assert_eq!(method.len(), 3);
46/// // Out of range: an empty slice, never a panic.
47/// assert_eq!(Span { start: 10, end: 99 }.get(head), b"");
48/// ```
49#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
50pub struct Span {
51    /// The first byte.
52    pub start: u32,
53    /// One past the last byte.
54    pub end: u32,
55}
56
57impl Span {
58    #[inline]
59    pub(crate) fn new(start: usize, end: usize) -> Self {
60        // Offsets are bounded by the buffer capacity, which `Limits` keeps
61        // far below `u32::MAX`.
62        Self {
63            start: start as u32,
64            end: end as u32,
65        }
66    }
67
68    /// The bytes of `head` the span covers; empty when the span lies
69    /// outside `head` or is reversed.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// let span = http_net::Span { start: 4, end: 5 };
75    /// assert_eq!(span.get(b"GET / HTTP/1.1"), b"/");
76    /// ```
77    #[inline]
78    #[must_use]
79    pub fn get<'b>(&self, head: &'b [u8]) -> &'b [u8] {
80        head.get(self.start as usize..self.end as usize)
81            .unwrap_or(&[])
82    }
83
84    /// The span's length in bytes (0 for a reversed span).
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// assert_eq!(http_net::Span { start: 2, end: 7 }.len(), 5);
90    /// ```
91    #[inline]
92    #[must_use]
93    pub const fn len(&self) -> u32 {
94        self.end.saturating_sub(self.start)
95    }
96
97    /// Whether the span covers no bytes.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// assert!(http_net::Span::default().is_empty());
103    /// ```
104    #[inline]
105    #[must_use]
106    pub const fn is_empty(&self) -> bool {
107        self.len() == 0
108    }
109
110    /// Whether the span lies inside a head of `len` bytes, in order.
111    pub(crate) const fn fits(&self, len: usize) -> bool {
112        self.start <= self.end && (self.end as usize) <= len
113    }
114}
115
116/// One field line of a head: the name's span and the value's span (the
117/// value without surrounding whitespace), as offsets into the head bytes.
118///
119/// # Examples
120///
121/// ```
122/// use http_net::{ServerConn, ServerEvent};
123///
124/// let mut conn = ServerConn::new();
125/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost:  a \r\n\r\n");
126/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
127/// let raw = req.raw();
128/// let host = raw.fields()[0];
129/// assert_eq!(host.name.get(raw.bytes()), b"Host");
130/// assert_eq!(host.value.get(raw.bytes()), b"a");
131/// ```
132#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
133pub struct FieldSpan {
134    /// The field name, as received.
135    pub name: Span,
136    /// The field value, without leading or trailing whitespace.
137    pub value: Span,
138}
139
140/// The connections' own name for a field record.
141pub(crate) type Field = FieldSpan;
142
143/// Removes the fields a trailer section may not carry and a recipient
144/// could act on if it merged them into the head: framing
145/// (`content-length`, `transfer-encoding`) and routing (`host`), RFC 9110
146/// section 6.5.1. They never frame the message here; dropping them keeps a
147/// proxy or an application from relaying or merging them.
148pub(crate) fn drop_forbidden_trailers(head: &[u8], fields: &mut Vec<Field>) {
149    fields.retain(|f| {
150        let name = f.name.get(head);
151        !(name.eq_ignore_ascii_case(b"content-length")
152            || name.eq_ignore_ascii_case(b"transfer-encoding")
153            || name.eq_ignore_ascii_case(b"host"))
154    });
155}
156
157/// Where scanned field records go: the connection's reusable vector, a
158/// caller's slice (the stateless parsers, which allocate nothing), or
159/// nowhere (trailers that are validated and discarded).
160pub(crate) trait FieldSink {
161    fn put(&mut self, field: Field) -> Result<(), HttpError>;
162}
163
164impl FieldSink for Vec<Field> {
165    #[inline]
166    fn put(&mut self, field: Field) -> Result<(), HttpError> {
167        self.push(field);
168        Ok(())
169    }
170}
171
172/// Validates fields without keeping them.
173pub(crate) struct Discard;
174
175impl FieldSink for Discard {
176    #[inline]
177    fn put(&mut self, _field: Field) -> Result<(), HttpError> {
178        Ok(())
179    }
180}
181
182/// Fills a caller's slice; a field that does not fit is `TooManyHeaders`.
183pub(crate) struct SliceSink<'s> {
184    slots: &'s mut [Field],
185    len: usize,
186}
187
188impl<'s> SliceSink<'s> {
189    pub(crate) fn new(slots: &'s mut [Field]) -> Self {
190        Self { slots, len: 0 }
191    }
192
193    /// The slice back, and how many records were written to its front.
194    pub(crate) fn into_parts(self) -> (&'s mut [Field], usize) {
195        (self.slots, self.len)
196    }
197}
198
199impl FieldSink for SliceSink<'_> {
200    #[inline]
201    fn put(&mut self, field: Field) -> Result<(), HttpError> {
202        let slot = self
203            .slots
204            .get_mut(self.len)
205            .ok_or(HttpError::TooManyHeaders)?;
206        *slot = field;
207        self.len += 1;
208        Ok(())
209    }
210}
211
212#[derive(Clone, Copy, Debug, PartialEq, Eq)]
213pub(crate) enum HeadKind {
214    Request,
215    Response,
216    Trailer,
217}
218
219#[derive(Debug, PartialEq, Eq)]
220pub(crate) enum Scan {
221    Partial,
222    /// The head is complete; the value is its length including the blank line.
223    Done(usize),
224}
225
226/// Finds the next CRLF-terminated line starting at `line_start`, resuming
227/// the search at `*scan`. Returns the end of the line content (the index of
228/// its CR). `budget` bounds the line length including CRLF.
229pub(crate) fn find_line(
230    msg: &[u8],
231    line_start: usize,
232    scan: &mut usize,
233    budget: usize,
234    too_long: HttpError,
235) -> Result<Option<usize>, HttpError> {
236    let from = (*scan).max(line_start);
237    let hay = msg.get(from..).unwrap_or(&[]);
238    match find_byte(b'\n', hay) {
239        Some(i) => {
240            let lf = from + i;
241            if lf + 1 - line_start > budget {
242                return Err(too_long);
243            }
244            if lf == line_start || msg.get(lf - 1) != Some(&b'\r') {
245                return Err(HttpError::BareLf);
246            }
247            *scan = lf + 1;
248            Ok(Some(lf - 1))
249        }
250        None => {
251            *scan = msg.len();
252            if msg.len().saturating_sub(line_start) >= budget {
253                Err(too_long)
254            } else {
255                Ok(None)
256            }
257        }
258    }
259}
260
261/// Resumable scanner over a head (start line plus field lines) or a trailer
262/// section (field lines only), keeping its fields in a reusable vector.
263pub(crate) struct HeadScanner {
264    lines: LineScan,
265    pub(crate) fields: Vec<Field>,
266}
267
268impl HeadScanner {
269    pub(crate) const fn new() -> Self {
270        Self {
271            lines: LineScan::new(),
272            fields: Vec::new(),
273        }
274    }
275
276    /// Prepares for the next message; keeps the field vector's allocation.
277    pub(crate) fn reset(&mut self) {
278        self.lines = LineScan::new();
279        self.fields.clear();
280    }
281
282    /// Fields scanned in the current section, stored or not.
283    pub(crate) fn field_count(&self) -> usize {
284        self.lines.count
285    }
286
287    pub(crate) fn start_line(&self) -> Span {
288        self.lines.start_line()
289    }
290
291    /// Scans `msg` (the bytes from the message start to the end of input).
292    /// With `store` the fields are kept in [`fields`](Self::fields);
293    /// otherwise they are validated and counted only.
294    #[inline]
295    pub(crate) fn advance(
296        &mut self,
297        msg: &[u8],
298        limits: &Limits,
299        kind: HeadKind,
300        store: bool,
301    ) -> Result<Scan, HttpError> {
302        if store {
303            self.lines.advance(msg, limits, kind, &mut self.fields)
304        } else {
305            self.lines.advance(msg, limits, kind, &mut Discard)
306        }
307    }
308}
309
310/// The line-by-line state of a head scan: where the search stopped and
311/// what has been counted. Shared by the connections and the stateless
312/// parsers; the fields go to a [`FieldSink`].
313pub(crate) struct LineScan {
314    scan: usize,
315    line_start: usize,
316    start_line: Option<Span>,
317    skipped: usize,
318    field_bytes: usize,
319    count: usize,
320}
321
322impl LineScan {
323    pub(crate) const fn new() -> Self {
324        Self {
325            scan: 0,
326            line_start: 0,
327            start_line: None,
328            skipped: 0,
329            field_bytes: 0,
330            count: 0,
331        }
332    }
333
334    pub(crate) fn start_line(&self) -> Span {
335        self.start_line.unwrap_or_default()
336    }
337
338    /// Scans `msg` (the bytes from the message start to the end of input),
339    /// handing each validated field to `sink`.
340    pub(crate) fn advance<S: FieldSink>(
341        &mut self,
342        msg: &[u8],
343        limits: &Limits,
344        kind: HeadKind,
345        sink: &mut S,
346    ) -> Result<Scan, HttpError> {
347        let (section_bytes, section_fields) = if kind == HeadKind::Trailer {
348            (limits.max_trailer_bytes(), limits.max_trailer_fields())
349        } else {
350            (limits.max_header_bytes(), limits.max_headers())
351        };
352        loop {
353            let in_start = kind != HeadKind::Trailer && self.start_line.is_none();
354            let (budget, too_long) = if in_start {
355                (
356                    limits.max_start_line().saturating_sub(self.skipped),
357                    HttpError::StartLineTooLong,
358                )
359            } else {
360                // One line may not exceed the field-line budget, nor what is
361                // left of the section; whichever is smaller decides the error.
362                let section = section_bytes.saturating_sub(self.field_bytes);
363                if limits.max_field_line() < section {
364                    (limits.max_field_line(), HttpError::FieldLineTooLong)
365                } else {
366                    (section, HttpError::HeadersTooLarge)
367                }
368            };
369            // The common field line in one pass. Anything else, and a line
370            // whose search already began on earlier input, takes the general
371            // path below, which decides exactly as it always has.
372            if !in_start && self.scan <= self.line_start {
373                if let Some((field, next)) = fast_field(msg, self.line_start) {
374                    let line_len = next - self.line_start;
375                    if line_len <= budget {
376                        self.scan = next;
377                        self.line_start = next;
378                        self.field_bytes += line_len;
379                        if self.field_bytes + 2 > section_bytes {
380                            return Err(HttpError::HeadersTooLarge);
381                        }
382                        if self.count >= section_fields {
383                            return Err(HttpError::TooManyHeaders);
384                        }
385                        self.count += 1;
386                        sink.put(field)?;
387                        continue;
388                    }
389                }
390            }
391            let Some(end) = find_line(msg, self.line_start, &mut self.scan, budget, too_long)?
392            else {
393                return Ok(Scan::Partial);
394            };
395            let start = self.line_start;
396            let line = msg.get(start..end).unwrap_or(&[]);
397            let line_len = self.scan - start;
398            self.line_start = self.scan;
399
400            if in_start {
401                if line.is_empty() {
402                    if kind == HeadKind::Request {
403                        // RFC 9112 section 2.2: ignore empty lines before the
404                        // request line. They count against its budget.
405                        self.skipped += line_len;
406                        continue;
407                    }
408                    return Err(HttpError::InvalidStartLine);
409                }
410                if find_byte(b'\r', line).is_some() {
411                    return Err(HttpError::BareCr);
412                }
413                self.start_line = Some(Span::new(start, end));
414                continue;
415            }
416            if line.is_empty() {
417                return Ok(Scan::Done(self.scan));
418            }
419            self.field_bytes += line_len;
420            // Every field line must leave room for the blank line that ends
421            // the section, so the section as a whole fits the budget.
422            if self.field_bytes + 2 > section_bytes {
423                return Err(HttpError::HeadersTooLarge);
424            }
425            if self.count >= section_fields {
426                return Err(HttpError::TooManyHeaders);
427            }
428            let field = parse_field(line, start)?;
429            self.count += 1;
430            sink.put(field)?;
431        }
432    }
433}
434
435/// Validates one field line (`line` starts at offset `base` in the head).
436// Forced inline: the scanner is compiled once per field sink, and without
437// it this per-field call stays out of line (about 8% on the head
438// benchmark, 12% on client response parsing).
439#[inline(always)]
440fn parse_field(line: &[u8], base: usize) -> Result<Field, HttpError> {
441    if line.first().is_some_and(|&b| is_ows(b)) {
442        return Err(HttpError::ObsFold);
443    }
444    let Some(colon) = find_byte(b':', line) else {
445        return Err(if find_byte(b'\r', line).is_some() {
446            HttpError::BareCr
447        } else {
448            HttpError::InvalidHeaderName
449        });
450    };
451    let name = &line[..colon];
452    if name.last().is_some_and(|&b| is_ows(b)) {
453        return Err(HttpError::WhitespaceBeforeColon);
454    }
455    if !name.iter().all(|&b| is_tchar(b)) || name.is_empty() {
456        return Err(if find_byte(b'\r', name).is_some() {
457            HttpError::BareCr
458        } else {
459            HttpError::InvalidHeaderName
460        });
461    }
462    let raw = &line[colon + 1..];
463    let lead = raw.iter().take_while(|&&b| is_ows(b)).count();
464    let value = trim_ows(raw);
465    check_field_value(value)?;
466    let value_start = base + colon + 1 + lead;
467    Ok(Field {
468        name: Span::new(base, base + colon),
469        value: Span::new(value_start, value_start + value.len()),
470    })
471}
472
473/// The common field line in one pass, the way it nearly always arrives: a
474/// token name, a colon, spaces, a value of printable ASCII, and CR LF, all
475/// in `msg` from `start`. Returns the field and the offset after its LF.
476///
477/// `None` for anything else (a tab, obs-text, a control byte, a bare CR or
478/// LF, a fold, a missing colon) and for a line not yet complete: the caller
479/// then takes the general path from the line's start, which accepts and
480/// refuses exactly as before. On every line this accepts, the general path
481/// gives the same field (`tests` below and the fuzz targets check it).
482#[inline(always)]
483fn fast_field(msg: &[u8], start: usize) -> Option<(Field, usize)> {
484    let line = msg.get(start..)?;
485    let colon = line.iter().position(|&b| !is_tchar(b))?;
486    if colon == 0 || line[colon] != b':' {
487        return None;
488    }
489    let mut value = colon + 1;
490    while line.get(value) == Some(&b' ') {
491        value += 1;
492    }
493    let cr = value + printable_run(&line[value..]);
494    if line.get(cr) != Some(&b'\r') || line.get(cr + 1) != Some(&b'\n') {
495        return None;
496    }
497    let mut value_end = cr;
498    while value_end > value && line[value_end - 1] == b' ' {
499        value_end -= 1;
500    }
501    Some((
502        Field {
503            name: Span::new(start, start + colon),
504            value: Span::new(start + value, start + value_end),
505        },
506        start + cr + 2,
507    ))
508}
509
510/// The HTTP version of a message.
511///
512/// # Examples
513///
514/// ```
515/// use http_net::Version;
516///
517/// assert_eq!(Version::Http11.as_str(), "HTTP/1.1");
518/// ```
519#[non_exhaustive]
520#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
521pub enum Version {
522    /// HTTP/1.0: no chunked encoding, keep-alive only when asked for.
523    Http10,
524    /// HTTP/1.1 (also used for HTTP/1.2 through 1.9, which RFC 9110 section
525    /// 2.5 says to process as the highest implemented minor version).
526    Http11,
527}
528
529impl Version {
530    /// The version's wire text.
531    ///
532    /// # Examples
533    ///
534    /// ```
535    /// assert_eq!(http_net::Version::Http10.as_str(), "HTTP/1.0");
536    /// ```
537    #[must_use]
538    pub const fn as_str(&self) -> &'static str {
539        match self {
540            Self::Http10 => "HTTP/1.0",
541            Self::Http11 => "HTTP/1.1",
542        }
543    }
544}
545
546/// How a message's body is delimited.
547///
548/// # Examples
549///
550/// ```
551/// use http_net::{BodyFraming, ServerConn, ServerEvent};
552///
553/// let mut conn = ServerConn::new();
554/// let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nContent-Length: 3\r\n\r\nabc");
555/// match conn.poll().unwrap() {
556///     ServerEvent::Request(req) => assert_eq!(req.framing(), BodyFraming::Length(3)),
557///     other => panic!("{other:?}"),
558/// }
559/// ```
560#[non_exhaustive]
561#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
562pub enum BodyFraming {
563    /// No body.
564    None,
565    /// Exactly this many bytes (`Content-Length`).
566    Length(u64),
567    /// `Transfer-Encoding: chunked`.
568    Chunked,
569    /// The body runs until the peer closes the connection (responses only).
570    UntilClose,
571}
572
573/// The form of a request target (RFC 9112 section 3.2).
574///
575/// # Examples
576///
577/// ```
578/// use http_net::{ServerConn, ServerEvent, TargetForm};
579///
580/// let mut conn = ServerConn::new();
581/// let _ = conn.feed(b"OPTIONS * HTTP/1.1\r\nHost: a\r\n\r\n");
582/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
583/// assert_eq!(req.target_form(), TargetForm::Asterisk);
584/// ```
585#[non_exhaustive]
586#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
587pub enum TargetForm {
588    /// `/path?query`: the usual form for requests to an origin server.
589    Origin,
590    /// `scheme://authority/path?query`: requests to a proxy (and, per RFC
591    /// 9112 section 3.2.2, acceptable to origin servers too).
592    Absolute,
593    /// `host:port`: only with `CONNECT`.
594    Authority,
595    /// `*`: only with `OPTIONS`, for the server as a whole.
596    Asterisk,
597}
598
599/// The `h2c` upgrade token, which is never treated as an upgrade offer
600/// (RFC 9113 section 3.1 deprecates it; forwarded blindly by a proxy, it is
601/// the h2c smuggling attack).
602pub(crate) fn is_h2c(protocol: &[u8]) -> bool {
603    let name = protocol
604        .iter()
605        .position(|&b| b == b'/')
606        .map_or(protocol, |i| &protocol[..i]);
607    name.eq_ignore_ascii_case(b"h2c")
608}
609
610/// Whether a `101` naming `chosen` answers an `Upgrade` offer `element`:
611/// ASCII case-insensitive, and a name without a version matches an offer of
612/// that name with any version (`websocket` answers `websocket/13`).
613pub(crate) fn protocol_matches(chosen: &[u8], element: &[u8]) -> bool {
614    if is_h2c(element) || is_h2c(chosen) {
615        return false;
616    }
617    if chosen.eq_ignore_ascii_case(element) {
618        return true;
619    }
620    !chosen.contains(&b'/')
621        && element
622            .iter()
623            .position(|&b| b == b'/')
624            .is_some_and(|i| element[..i].eq_ignore_ascii_case(chosen))
625}
626
627/// Whether a `101` switches only to protocols the request offered: the
628/// response's `Upgrade` fields name at least one protocol, and every one of
629/// them matches an element of `offer` (the request's `Upgrade` value).
630/// Names compare ASCII case-insensitively; a bare name matches a versioned
631/// one either way (`websocket` and `websocket/13`).
632pub(crate) fn switches_to_offered(head: &[u8], fields: &[Field], offer: &[u8]) -> bool {
633    let mut named = false;
634    for field in fields {
635        if !field.name.get(head).eq_ignore_ascii_case(b"upgrade") {
636            continue;
637        }
638        for chosen in list_elements(field.value.get(head)) {
639            named = true;
640            let offered = list_elements(offer)
641                .any(|o| protocol_matches(chosen, o) || protocol_matches(o, chosen));
642            if !offered {
643                return false;
644            }
645        }
646    }
647    named
648}
649
650pub(crate) fn parse_version(v: &[u8]) -> Result<Version, HttpError> {
651    match v {
652        [b'H', b'T', b'T', b'P', b'/', major, b'.', minor]
653            if major.is_ascii_digit() && minor.is_ascii_digit() =>
654        {
655            match (major, minor) {
656                (b'1', b'0') => Ok(Version::Http10),
657                (b'1', _) => Ok(Version::Http11),
658                _ => Err(HttpError::UnsupportedVersion),
659            }
660        }
661        _ => Err(HttpError::InvalidVersion),
662    }
663}
664
665/// What the framing-relevant fields of a message say.
666#[derive(Default)]
667struct FieldFacts {
668    content_length: Option<u64>,
669    te_seen: bool,
670    te_codings: usize,
671    te_chunked: usize,
672    te_last_chunked: bool,
673    te_other: bool,
674    close: bool,
675    keep_alive: bool,
676    upgrade_token: bool,
677    upgrade_field: bool,
678    /// An `Upgrade` element other than `h2c`.
679    upgrade_offer: bool,
680    expect_continue: bool,
681    /// An `Expect` element other than `100-continue`.
682    expect_other: bool,
683    hosts: usize,
684    host: Option<Span>,
685}
686
687fn scan_fields(head: &[u8], fields: &[Field]) -> Result<FieldFacts, HttpError> {
688    let mut facts = FieldFacts::default();
689    // The lengths of the six names below: most fields are ruled out before
690    // any compare.
691    const LENGTHS: u32 = (1 << 4) | (1 << 6) | (1 << 7) | (1 << 10) | (1 << 14) | (1 << 17);
692    for field in fields {
693        let name = field.name.get(head);
694        if name.len() > 17 || LENGTHS & (1 << name.len()) == 0 {
695            continue;
696        }
697        let value = field.value.get(head);
698        if name.eq_ignore_ascii_case(b"content-length") {
699            if facts.content_length.is_some() {
700                return Err(HttpError::DuplicateContentLength);
701            }
702            facts.content_length =
703                Some(parse_decimal(value).ok_or(HttpError::InvalidContentLength)?);
704        } else if name.eq_ignore_ascii_case(b"transfer-encoding") {
705            facts.te_seen = true;
706            for element in list_elements(value) {
707                let (coding, params) = match find_byte(b';', element) {
708                    Some(i) => (trim_ows(&element[..i]), true),
709                    None => (element, false),
710                };
711                if !is_token(coding) {
712                    return Err(HttpError::InvalidTransferEncoding);
713                }
714                facts.te_codings += 1;
715                if coding.eq_ignore_ascii_case(b"chunked") {
716                    if params {
717                        return Err(HttpError::InvalidTransferEncoding);
718                    }
719                    facts.te_chunked += 1;
720                    facts.te_last_chunked = true;
721                } else {
722                    facts.te_other = true;
723                    facts.te_last_chunked = false;
724                }
725            }
726        } else if name.eq_ignore_ascii_case(b"connection") {
727            for token in list_elements(value) {
728                if token.eq_ignore_ascii_case(b"close") {
729                    facts.close = true;
730                } else if token.eq_ignore_ascii_case(b"keep-alive") {
731                    facts.keep_alive = true;
732                } else if token.eq_ignore_ascii_case(b"upgrade") {
733                    facts.upgrade_token = true;
734                }
735            }
736        } else if name.eq_ignore_ascii_case(b"upgrade") {
737            facts.upgrade_field |= !value.is_empty();
738            facts.upgrade_offer |= list_elements(value).any(|e| !is_h2c(e));
739        } else if name.eq_ignore_ascii_case(b"host") {
740            facts.hosts += 1;
741            facts.host = Some(field.value);
742        } else if name.eq_ignore_ascii_case(b"expect") {
743            // RFC 9110 section 10.1.1: the expectation is case-insensitive.
744            for e in list_elements(value) {
745                if e.eq_ignore_ascii_case(b"100-continue") {
746                    facts.expect_continue = true;
747                } else {
748                    facts.expect_other = true;
749                }
750            }
751        }
752    }
753    Ok(facts)
754}
755
756/// Applies RFC 9112 section 6 to the transfer-coding facts.
757fn transfer_framing(
758    facts: &FieldFacts,
759    version: Version,
760) -> Result<Option<BodyFraming>, HttpError> {
761    if !facts.te_seen {
762        return Ok(None);
763    }
764    if version == Version::Http10 {
765        return Err(HttpError::TransferEncodingInHttp10);
766    }
767    if facts.content_length.is_some() {
768        return Err(HttpError::ConflictingFraming);
769    }
770    if facts.te_codings == 0 || facts.te_chunked > 1 || !facts.te_last_chunked {
771        return Err(HttpError::InvalidTransferEncoding);
772    }
773    if facts.te_other {
774        return Err(HttpError::UnsupportedTransferEncoding);
775    }
776    Ok(Some(BodyFraming::Chunked))
777}
778
779/// Everything learned from a request head. Spans are offsets into the head
780/// bytes, so the facts stay valid when the bytes are copied.
781#[derive(Clone, Copy, Debug, PartialEq, Eq)]
782pub(crate) struct RequestInfo {
783    pub(crate) method: Method,
784    pub(crate) start_line: Span,
785    pub(crate) method_span: Span,
786    pub(crate) target: Span,
787    target_form: TargetForm,
788    pub(crate) version: Version,
789    pub(crate) framing: BodyFraming,
790    content_length: Option<u64>,
791    pub(crate) keep_alive: bool,
792    pub(crate) upgrade: bool,
793    pub(crate) expect_continue: bool,
794    unknown_expectation: bool,
795    pub(crate) host: Option<Span>,
796    /// The authority of an absolute-form target, which replaces `Host`.
797    pub(crate) authority: Option<Span>,
798    /// The path-and-query part of the target: the whole target except for
799    /// the absolute form, where it is what follows the authority.
800    pub(crate) origin: Span,
801}
802
803impl RequestInfo {
804    pub(crate) const EMPTY: Self = Self {
805        method: Method::Get,
806        start_line: Span { start: 0, end: 0 },
807        method_span: Span { start: 0, end: 0 },
808        target: Span { start: 0, end: 0 },
809        target_form: TargetForm::Origin,
810        version: Version::Http11,
811        framing: BodyFraming::None,
812        content_length: None,
813        keep_alive: false,
814        upgrade: false,
815        expect_continue: false,
816        unknown_expectation: false,
817        host: None,
818        authority: None,
819        origin: Span { start: 0, end: 0 },
820    };
821}
822
823/// Validates a request target against the forms its method allows.
824pub(crate) fn check_target(method: Method, target: &[u8]) -> Result<(), HttpError> {
825    let ok = match target.first() {
826        None => false,
827        Some(b'/') => method != Method::Connect && is_target_chars(target),
828        Some(b'*') if target.len() == 1 => method == Method::Options,
829        Some(_) if method == Method::Connect => {
830            // authority-form: host ":" port, with a non-empty host and port.
831            is_authority(target)
832                && target
833                    .iter()
834                    .rposition(|&b| b == b':')
835                    .is_some_and(|c| c + 1 < target.len() && !target[c..].contains(&b']'))
836        }
837        Some(_) => split_absolute_form(target).is_some(),
838    };
839    if ok {
840        Ok(())
841    } else {
842        Err(HttpError::InvalidTarget)
843    }
844}
845
846/// `host [":" port]` with a non-empty host: RFC 9110 section 4.2.1 makes an
847/// empty host in an `http` URI invalid.
848fn is_authority(s: &[u8]) -> bool {
849    !s.is_empty() && s[0] != b':' && is_host_value(s)
850}
851
852/// Splits an absolute-form target, `scheme "://" authority path-abempty
853/// [ "?" query ]`, returning the authority's range within it.
854///
855/// Only the hierarchical form with an authority is accepted: it is the form
856/// RFC 9112 section 3.2.2 describes (requests to proxies, and future
857/// requests to origin servers), and it is the only one that names the host
858/// the request is for. Userinfo is refused (RFC 9110 section 4.2.4 says to
859/// treat it as an error), as is an empty host.
860fn split_absolute_form(target: &[u8]) -> Option<(usize, usize)> {
861    let colon = find_byte(b':', target)?;
862    let scheme = &target[..colon];
863    let scheme_ok = scheme.first().is_some_and(u8::is_ascii_alphabetic)
864        && scheme
865            .iter()
866            .all(|&b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'));
867    if !scheme_ok || !target[colon..].starts_with(b"://") {
868        return None;
869    }
870    let auth_start = colon + 3;
871    let after = &target[auth_start..];
872    let auth_len = after
873        .iter()
874        .position(|&b| b == b'/' || b == b'?')
875        .unwrap_or(after.len());
876    let authority = &after[..auth_len];
877    let rest = &after[auth_len..];
878    (is_authority(authority) && is_target_chars(rest))
879        .then_some((auth_start, auth_start + auth_len))
880}
881
882pub(crate) fn interpret_request(
883    head: &[u8],
884    start: Span,
885    fields: &[Field],
886    limits: &Limits,
887) -> Result<RequestInfo, HttpError> {
888    let line = start.get(head);
889    let base = start.start as usize;
890    let sp1 = find_byte(b' ', line).ok_or(HttpError::InvalidStartLine)?;
891    let sp2 = line
892        .iter()
893        .rposition(|&b| b == b' ')
894        .ok_or(HttpError::InvalidStartLine)?;
895    if sp2 == sp1 {
896        return Err(HttpError::InvalidStartLine);
897    }
898    let method_bytes = &line[..sp1];
899    if !is_token(method_bytes) {
900        return Err(HttpError::InvalidMethod);
901    }
902    let version = parse_version(&line[sp2 + 1..])?;
903    let method = Method::from_bytes(method_bytes);
904    let target = &line[sp1 + 1..sp2];
905    check_target(method, target)?;
906    let target_start = base + sp1 + 1;
907    let target_span = Span::new(target_start, base + sp2);
908    let (target_form, authority, origin) = match target.first() {
909        Some(b'/') => (TargetForm::Origin, None, target_span),
910        Some(b'*') => (TargetForm::Asterisk, None, target_span),
911        _ if method == Method::Connect => (TargetForm::Authority, None, target_span),
912        _ => match split_absolute_form(target) {
913            Some((a, b)) => (
914                TargetForm::Absolute,
915                Some(Span::new(target_start + a, target_start + b)),
916                Span::new(target_start + b, base + sp2),
917            ),
918            None => return Err(HttpError::InvalidTarget),
919        },
920    };
921
922    let facts = scan_fields(head, fields)?;
923    let framing = match transfer_framing(&facts, version)? {
924        Some(f) => f,
925        None => match facts.content_length {
926            Some(n) if n > limits.max_body() => return Err(HttpError::BodyTooLarge),
927            Some(0) | None => BodyFraming::None,
928            Some(n) => BodyFraming::Length(n),
929        },
930    };
931    if facts.hosts > 1 {
932        return Err(HttpError::InvalidHost);
933    }
934    if let Some(host) = facts.host {
935        if !is_host_value(host.get(head)) {
936            return Err(HttpError::InvalidHost);
937        }
938    } else if version == Version::Http11 {
939        return Err(HttpError::MissingHost);
940    }
941    let keep_alive = match version {
942        Version::Http11 => !facts.close,
943        Version::Http10 => facts.keep_alive && !facts.close,
944    };
945    Ok(RequestInfo {
946        method,
947        start_line: start,
948        method_span: Span::new(base, base + sp1),
949        target: target_span,
950        target_form,
951        version,
952        framing,
953        content_length: facts.content_length,
954        keep_alive,
955        // RFC 9110 section 7.8: Upgrade in an HTTP/1.0 request is ignored.
956        // An offer of only `h2c` is no offer: the request is served as
957        // HTTP/1.1 (RFC 9113 section 3.1).
958        upgrade: version == Version::Http11 && facts.upgrade_token && facts.upgrade_offer,
959        // Reported for any version, so the caller can answer 417 (RFC 9110
960        // section 10.1.1 MAY); it never changes framing.
961        unknown_expectation: facts.expect_other,
962        // RFC 9110 section 10.1.1: ignored in HTTP/1.0, and meaningless
963        // without a body to wait for.
964        expect_continue: version == Version::Http11
965            && facts.expect_continue
966            && framing != BodyFraming::None,
967        host: facts.host,
968        authority,
969        origin,
970    })
971}
972
973/// Everything learned from a response head.
974#[derive(Clone, Copy, Debug, PartialEq, Eq)]
975pub(crate) struct ResponseInfo {
976    pub(crate) status: u16,
977    pub(crate) start_line: Span,
978    reason: Span,
979    pub(crate) version: Version,
980    pub(crate) framing: BodyFraming,
981    content_length: Option<u64>,
982    pub(crate) keep_alive: bool,
983    pub(crate) upgrade_field: bool,
984}
985
986impl ResponseInfo {
987    pub(crate) const EMPTY: Self = Self {
988        status: 0,
989        start_line: Span { start: 0, end: 0 },
990        reason: Span { start: 0, end: 0 },
991        version: Version::Http11,
992        framing: BodyFraming::None,
993        content_length: None,
994        keep_alive: false,
995        upgrade_field: false,
996    };
997}
998
999/// What the request asked for, which decides how its response is framed
1000/// (RFC 9112 section 6.3): a response to `HEAD` has no body whatever its
1001/// fields say, and a 2xx to `CONNECT` turns the connection into a tunnel.
1002#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
1003pub(crate) struct Asked {
1004    /// The request was `HEAD`.
1005    pub(crate) head: bool,
1006    /// The request was `CONNECT`.
1007    pub(crate) connect: bool,
1008}
1009
1010impl Asked {
1011    /// The facts of a request with `method`.
1012    pub(crate) fn from_method(method: Method) -> Self {
1013        Self {
1014            head: method == Method::Head,
1015            connect: method == Method::Connect,
1016        }
1017    }
1018}
1019
1020pub(crate) fn interpret_response(
1021    head: &[u8],
1022    start: Span,
1023    fields: &[Field],
1024    limits: &Limits,
1025    asked: Asked,
1026) -> Result<ResponseInfo, HttpError> {
1027    let line = start.get(head);
1028    let base = start.start as usize;
1029    // status-line = HTTP-version SP status-code SP [ reason-phrase ]
1030    // The SP after the code is required of senders, but some servers omit
1031    // it when the reason is empty (`HTTP/1.1 200`); accepting that cannot
1032    // change framing, so the client does (RFC 9112 section 4).
1033    if line.len() < 12 || line[8] != b' ' || (line.len() > 12 && line[12] != b' ') {
1034        return Err(HttpError::InvalidStartLine);
1035    }
1036    let version = parse_version(&line[..8])?;
1037    let code = &line[9..12];
1038    if !code.iter().all(u8::is_ascii_digit) {
1039        return Err(HttpError::InvalidStatus);
1040    }
1041    let status = code
1042        .iter()
1043        .fold(0u16, |acc, &d| acc * 10 + u16::from(d - b'0'));
1044    if !(100..=599).contains(&status) {
1045        return Err(HttpError::InvalidStatus);
1046    }
1047    let reason_start = line.len().min(13);
1048    let reason = &line[reason_start..];
1049    if !is_reason(reason) {
1050        return Err(HttpError::InvalidStartLine);
1051    }
1052
1053    let facts = scan_fields(head, fields)?;
1054    let bodiless = asked.head
1055        || (100..200).contains(&status)
1056        || status == 204
1057        || status == 304
1058        || (asked.connect && (200..300).contains(&status));
1059    let framing = if bodiless {
1060        BodyFraming::None
1061    } else {
1062        match transfer_framing(&facts, version)? {
1063            Some(f) => f,
1064            None => match facts.content_length {
1065                Some(n) if n > limits.max_body() => return Err(HttpError::BodyTooLarge),
1066                Some(0) => BodyFraming::None,
1067                Some(n) => BodyFraming::Length(n),
1068                None => BodyFraming::UntilClose,
1069            },
1070        }
1071    };
1072    let keep_alive = framing != BodyFraming::UntilClose
1073        && match version {
1074            Version::Http11 => !facts.close,
1075            Version::Http10 => facts.keep_alive && !facts.close,
1076        };
1077    Ok(ResponseInfo {
1078        status,
1079        start_line: start,
1080        reason: Span::new(base + reason_start, base + line.len()),
1081        version,
1082        framing,
1083        content_length: facts.content_length,
1084        keep_alive,
1085        upgrade_field: facts.upgrade_field,
1086    })
1087}
1088
1089/// Iterator over a head's fields as `(name, value)` pairs, in arrival order.
1090///
1091/// Names are returned as received (field names are case-insensitive; compare
1092/// with `eq_ignore_ascii_case`). Values have surrounding whitespace removed
1093/// and may contain any byte RFC 9110 allows, including `obs-text` above
1094/// 0x7F, so they are bytes rather than `str`.
1095///
1096/// # Examples
1097///
1098/// ```
1099/// use http_net::{ServerConn, ServerEvent};
1100///
1101/// let mut conn = ServerConn::new();
1102/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nX-One: 1\r\n\r\n");
1103/// if let ServerEvent::Request(req) = conn.poll().unwrap() {
1104///     let names: Vec<&str> = req.headers().map(|(n, _)| n).collect();
1105///     assert_eq!(names, ["Host", "X-One"]);
1106/// }
1107/// ```
1108#[derive(Clone)]
1109pub struct Headers<'a> {
1110    head: &'a [u8],
1111    fields: slice::Iter<'a, Field>,
1112}
1113
1114impl<'a> Headers<'a> {
1115    pub(crate) fn new(head: &'a [u8], fields: &'a [Field]) -> Self {
1116        Self {
1117            head,
1118            fields: fields.iter(),
1119        }
1120    }
1121}
1122
1123impl<'a> Iterator for Headers<'a> {
1124    type Item = (&'a str, &'a [u8]);
1125
1126    #[inline]
1127    fn next(&mut self) -> Option<Self::Item> {
1128        let field = self.fields.next()?;
1129        Some((
1130            core::str::from_utf8(field.name.get(self.head)).unwrap_or(""),
1131            field.value.get(self.head),
1132        ))
1133    }
1134
1135    #[inline]
1136    fn size_hint(&self) -> (usize, Option<usize>) {
1137        self.fields.size_hint()
1138    }
1139}
1140
1141impl ExactSizeIterator for Headers<'_> {}
1142
1143/// Shows the fields as `(name, value)` pairs; the values of credential
1144/// fields (`authorization`, `proxy-authorization`, `cookie`, `set-cookie`)
1145/// are replaced by `<redacted N bytes>`.
1146impl fmt::Debug for Headers<'_> {
1147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1148        let head = self.head;
1149        f.debug_list()
1150            .entries(self.fields.clone().map(|field| {
1151                let name = field.name.get(head);
1152                (
1153                    FieldName(name),
1154                    FieldValue {
1155                        name,
1156                        value: field.value.get(head),
1157                    },
1158                )
1159            }))
1160            .finish()
1161    }
1162}
1163
1164/// Iterator over the values of every field with one name, in arrival
1165/// order: what [`RequestHead::header_all`] and
1166/// [`ResponseHead::header_all`] return. Each `Set-Cookie`, for example, is
1167/// its own field and its own item; nothing is comma-joined.
1168///
1169/// # Examples
1170///
1171/// ```
1172/// use http_net::{ServerConn, ServerEvent};
1173///
1174/// let mut conn = ServerConn::new();
1175/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nVia: 1.1 p1\r\nVia: 1.1 p2\r\n\r\n");
1176/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1177/// let vias: Vec<&[u8]> = req.header_all("via").collect();
1178/// assert_eq!(vias, [&b"1.1 p1"[..], &b"1.1 p2"[..]]);
1179/// ```
1180///
1181/// The values borrow the head (`'a`), not the name (`'n`), so they outlive
1182/// a temporary name used for the lookup.
1183#[derive(Clone)]
1184pub struct HeaderValues<'a, 'n> {
1185    head: &'a [u8],
1186    fields: slice::Iter<'a, Field>,
1187    name: &'n [u8],
1188}
1189
1190impl<'a> Iterator for HeaderValues<'a, '_> {
1191    type Item = &'a [u8];
1192
1193    #[inline]
1194    fn next(&mut self) -> Option<Self::Item> {
1195        let (head, name) = (self.head, self.name);
1196        self.fields
1197            .find(|f| f.name.get(head).eq_ignore_ascii_case(name))
1198            .map(|f| f.value.get(head))
1199    }
1200
1201    #[inline]
1202    fn size_hint(&self) -> (usize, Option<usize>) {
1203        (0, self.fields.size_hint().1)
1204    }
1205}
1206
1207impl fmt::Debug for HeaderValues<'_, '_> {
1208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1209        let name = self.name;
1210        f.debug_list()
1211            .entries(self.clone().map(|value| FieldValue { name, value }))
1212            .finish()
1213    }
1214}
1215
1216/// Iterator over the elements of a list field (`#rule`) across every line
1217/// with one name: what [`RequestHead::header_list`],
1218/// [`ResponseHead::header_list`], [`RequestHead::upgrade_protocols`], and
1219/// [`RequestHead::connection_options`] return. Elements are trimmed of whitespace, empty ones are skipped, and
1220/// a comma inside a quoted string does not split an element.
1221///
1222/// # Examples
1223///
1224/// ```
1225/// use http_net::{ServerConn, ServerEvent};
1226///
1227/// let mut conn = ServerConn::new();
1228/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive, X-Trace\r\n\r\n");
1229/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1230/// let options: Vec<&[u8]> = req.header_list("connection").collect();
1231/// assert_eq!(options, [&b"keep-alive"[..], b"X-Trace"]);
1232/// ```
1233#[derive(Clone)]
1234pub struct ListElements<'a, 'n> {
1235    head: &'a [u8],
1236    fields: slice::Iter<'a, Field>,
1237    name: &'n [u8],
1238    current: ListSplit<'a>,
1239    skip_h2c: bool,
1240}
1241
1242impl<'a> Iterator for ListElements<'a, '_> {
1243    type Item = &'a [u8];
1244
1245    fn next(&mut self) -> Option<Self::Item> {
1246        loop {
1247            if let Some(e) = self.current.next() {
1248                if self.skip_h2c && is_h2c(e) {
1249                    continue;
1250                }
1251                return Some(e);
1252            }
1253            let (head, name) = (self.head, self.name);
1254            let field = self
1255                .fields
1256                .find(|f| f.name.get(head).eq_ignore_ascii_case(name))?;
1257            self.current = list_elements(field.value.get(head));
1258        }
1259    }
1260}
1261
1262impl fmt::Debug for ListElements<'_, '_> {
1263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1264        let name = self.name;
1265        f.debug_list()
1266            .entries(self.clone().map(|value| FieldValue { name, value }))
1267            .finish()
1268    }
1269}
1270
1271fn list_values<'a, 'n>(head: &'a [u8], fields: &'a [Field], name: &'n str) -> ListElements<'a, 'n> {
1272    ListElements {
1273        head,
1274        fields: fields.iter(),
1275        name: name.as_bytes(),
1276        current: list_elements(&[]),
1277        skip_h2c: false,
1278    }
1279}
1280
1281fn find_header<'a>(head: &'a [u8], fields: &[Field], name: &str) -> Option<&'a [u8]> {
1282    fields
1283        .iter()
1284        .find(|f| f.name.get(head).eq_ignore_ascii_case(name.as_bytes()))
1285        .map(|f| f.value.get(head))
1286}
1287
1288fn header_values<'a, 'n>(
1289    head: &'a [u8],
1290    fields: &'a [Field],
1291    name: &'n str,
1292) -> HeaderValues<'a, 'n> {
1293    HeaderValues {
1294        head,
1295        fields: fields.iter(),
1296        name: name.as_bytes(),
1297    }
1298}
1299
1300/// A parsed request head, borrowed from the connection's buffer.
1301///
1302/// Every accessor is a slice of the bytes that arrived; nothing is copied.
1303/// The view stays valid until the next call that mutates the connection.
1304/// Read it again later with [`ServerConn::request`](crate::ServerConn::request).
1305///
1306/// # Examples
1307///
1308/// ```
1309/// use http_net::{Method, ServerConn, ServerEvent, Version};
1310///
1311/// let mut conn = ServerConn::new();
1312/// let _ = conn.feed(b"GET /search?q=rust HTTP/1.1\r\nHost: example.com\r\n\r\n");
1313/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1314/// assert_eq!(req.method(), Method::Get);
1315/// assert_eq!(req.path(), "/search");
1316/// assert_eq!(req.query(), Some("q=rust"));
1317/// assert_eq!(req.version(), Version::Http11);
1318/// assert_eq!(req.host(), Some("example.com"));
1319/// assert!(req.keep_alive());
1320/// ```
1321#[derive(Clone, Copy)]
1322pub struct RequestHead<'a> {
1323    head: &'a [u8],
1324    fields: &'a [Field],
1325    info: &'a RequestInfo,
1326}
1327
1328impl<'a> RequestHead<'a> {
1329    pub(crate) const fn new(head: &'a [u8], fields: &'a [Field], info: &'a RequestInfo) -> Self {
1330        Self { head, fields, info }
1331    }
1332
1333    /// The bytes the spans index (the head, possibly followed by more
1334    /// input), the field records, and the interpreted facts.
1335    pub(crate) const fn parts(&self) -> (&'a [u8], &'a [Field], &'a RequestInfo) {
1336        (self.head, self.fields, self.info)
1337    }
1338
1339    /// The method, classified.
1340    ///
1341    /// # Examples
1342    ///
1343    /// ```
1344    /// # use http_net::{Method, ServerConn, ServerEvent};
1345    /// # let mut conn = ServerConn::new();
1346    /// # let _ = conn.feed(b"DELETE /x HTTP/1.1\r\nHost: a\r\n\r\n");
1347    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1348    /// assert_eq!(req.method(), Method::Delete);
1349    /// ```
1350    #[must_use]
1351    pub fn method(&self) -> Method {
1352        self.info.method
1353    }
1354
1355    /// The method exactly as received.
1356    ///
1357    /// # Examples
1358    ///
1359    /// ```
1360    /// # use http_net::{Method, ServerConn, ServerEvent};
1361    /// # let mut conn = ServerConn::new();
1362    /// # let _ = conn.feed(b"PROPFIND /x HTTP/1.1\r\nHost: a\r\n\r\n");
1363    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1364    /// assert_eq!(req.method(), Method::Other);
1365    /// assert_eq!(req.method_str(), "PROPFIND");
1366    /// ```
1367    #[must_use]
1368    pub fn method_str(&self) -> &'a str {
1369        core::str::from_utf8(self.info.method_span.get(self.head)).unwrap_or("")
1370    }
1371
1372    /// The request target exactly as received (origin form `/path?query`,
1373    /// absolute form, authority form for `CONNECT`, or `*`).
1374    ///
1375    /// # Examples
1376    ///
1377    /// ```
1378    /// # use http_net::{ServerConn, ServerEvent};
1379    /// # let mut conn = ServerConn::new();
1380    /// # let _ = conn.feed(b"GET /a%20b?x=1 HTTP/1.1\r\nHost: a\r\n\r\n");
1381    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1382    /// assert_eq!(req.target(), "/a%20b?x=1");
1383    /// ```
1384    #[must_use]
1385    pub fn target(&self) -> &'a str {
1386        core::str::from_utf8(self.info.target.get(self.head)).unwrap_or("")
1387    }
1388
1389    /// Which of the four RFC 9112 section 3.2 forms the target uses.
1390    ///
1391    /// # Examples
1392    ///
1393    /// ```
1394    /// # use http_net::{ServerConn, ServerEvent, TargetForm};
1395    /// # let mut conn = ServerConn::new();
1396    /// # let _ = conn.feed(b"GET http://a.test/x HTTP/1.1\r\nHost: a.test\r\n\r\n");
1397    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1398    /// assert_eq!(req.target_form(), TargetForm::Absolute);
1399    /// ```
1400    #[must_use]
1401    pub fn target_form(&self) -> TargetForm {
1402        self.info.target_form
1403    }
1404
1405    /// The path: the target up to (not including) the first `?`, with
1406    /// percent-encoding left as received.
1407    ///
1408    /// For an absolute-form target (`http://host/p?q`) this is the path
1409    /// after the authority (`/p`), and `/` when that path is empty, so a
1410    /// router sees the same path whichever form the client used. For `*`
1411    /// and for `CONNECT`'s authority form it is the whole target.
1412    ///
1413    /// # Examples
1414    ///
1415    /// ```
1416    /// # use http_net::{ServerConn, ServerEvent};
1417    /// # let mut conn = ServerConn::new();
1418    /// # let _ = conn.feed(b"GET /files/a.txt?v=2 HTTP/1.1\r\nHost: a\r\n\r\n");
1419    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1420    /// assert_eq!(req.path(), "/files/a.txt");
1421    ///
1422    /// # let mut conn = ServerConn::new();
1423    /// # let _ = conn.feed(b"GET http://a/files/b.txt HTTP/1.1\r\nHost: a\r\n\r\n");
1424    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1425    /// assert_eq!(req.path(), "/files/b.txt");
1426    /// ```
1427    #[must_use]
1428    pub fn path(&self) -> &'a str {
1429        let origin = self.origin();
1430        let path = origin.split_once('?').map_or(origin, |(p, _)| p);
1431        if path.is_empty() && self.info.authority.is_some() {
1432            // RFC 9110 section 4.2.3: an empty path in an http URI is "/".
1433            "/"
1434        } else {
1435            path
1436        }
1437    }
1438
1439    /// The query after the first `?`, if there is one.
1440    ///
1441    /// # Examples
1442    ///
1443    /// ```
1444    /// # use http_net::{ServerConn, ServerEvent};
1445    /// # let mut conn = ServerConn::new();
1446    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\n\r\n");
1447    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1448    /// assert_eq!(req.query(), None);
1449    /// ```
1450    #[must_use]
1451    pub fn query(&self) -> Option<&'a str> {
1452        self.origin().split_once('?').map(|(_, q)| q)
1453    }
1454
1455    /// The path-and-query part of the target.
1456    fn origin(&self) -> &'a str {
1457        core::str::from_utf8(self.info.origin.get(self.head)).unwrap_or("")
1458    }
1459
1460    /// The protocol version.
1461    ///
1462    /// # Examples
1463    ///
1464    /// ```
1465    /// # use http_net::{ServerConn, ServerEvent, Version};
1466    /// # let mut conn = ServerConn::new();
1467    /// # let _ = conn.feed(b"GET /x HTTP/1.0\r\n\r\n");
1468    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1469    /// assert_eq!(req.version(), Version::Http10);
1470    /// ```
1471    #[must_use]
1472    pub fn version(&self) -> Version {
1473        self.info.version
1474    }
1475
1476    /// All fields in arrival order.
1477    ///
1478    /// # Examples
1479    ///
1480    /// ```
1481    /// # use http_net::{ServerConn, ServerEvent};
1482    /// # let mut conn = ServerConn::new();
1483    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nAccept: */*\r\n\r\n");
1484    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1485    /// assert_eq!(req.headers().len(), 2);
1486    /// ```
1487    #[must_use]
1488    pub fn headers(&self) -> Headers<'a> {
1489        Headers {
1490            head: self.head,
1491            fields: self.fields.iter(),
1492        }
1493    }
1494
1495    /// The value of the first field named `name` (ASCII case-insensitive).
1496    ///
1497    /// # Examples
1498    ///
1499    /// ```
1500    /// # use http_net::{ServerConn, ServerEvent};
1501    /// # let mut conn = ServerConn::new();
1502    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nAccept:  text/html \r\n\r\n");
1503    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1504    /// assert_eq!(req.header("accept"), Some(&b"text/html"[..]));
1505    /// assert_eq!(req.header("cookie"), None);
1506    /// ```
1507    #[must_use]
1508    pub fn header(&self, name: &str) -> Option<&'a [u8]> {
1509        find_header(self.head, self.fields, name)
1510    }
1511
1512    /// Like [`header`](Self::header), but only when the value is UTF-8.
1513    ///
1514    /// # Examples
1515    ///
1516    /// ```
1517    /// # use http_net::{ServerConn, ServerEvent};
1518    /// # let mut conn = ServerConn::new();
1519    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nX: \xff\r\n\r\n");
1520    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1521    /// assert_eq!(req.header_str("host"), Some("a"));
1522    /// assert_eq!(req.header_str("x"), None);
1523    /// ```
1524    #[must_use]
1525    pub fn header_str(&self, name: &str) -> Option<&'a str> {
1526        self.header(name).and_then(|v| core::str::from_utf8(v).ok())
1527    }
1528
1529    /// The values of every field named `name` (ASCII case-insensitive), in
1530    /// arrival order: for fields that may be repeated, such as `via`,
1531    /// `forwarded`, or `cookie` from clients that send one line per cookie.
1532    ///
1533    /// # Examples
1534    ///
1535    /// ```
1536    /// # use http_net::{ServerConn, ServerEvent};
1537    /// # let mut conn = ServerConn::new();
1538    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nCookie: a=1\r\nCookie: b=2\r\n\r\n");
1539    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1540    /// let cookies: Vec<&[u8]> = req.header_all("cookie").collect();
1541    /// assert_eq!(cookies, [&b"a=1"[..], &b"b=2"[..]]);
1542    /// assert_eq!(req.header_all("accept").count(), 0);
1543    ///
1544    /// // The values borrow the head, not the name.
1545    /// let first = {
1546    ///     let name = String::from("COOKIE");
1547    ///     req.header_all(&name).next()
1548    /// };
1549    /// assert_eq!(first, Some(&b"a=1"[..]));
1550    /// ```
1551    #[must_use]
1552    pub fn header_all<'n>(&self, name: &'n str) -> HeaderValues<'a, 'n> {
1553        header_values(self.head, self.fields, name)
1554    }
1555
1556    /// The declared `Content-Length`, if the request has one. Unlike
1557    /// [`framing`](Self::framing), which reports `Content-Length: 0` as
1558    /// [`BodyFraming::None`], this tells `Some(0)` from an absent field.
1559    ///
1560    /// # Examples
1561    ///
1562    /// ```
1563    /// # use http_net::{BodyFraming, ServerConn, ServerEvent};
1564    /// # let mut conn = ServerConn::new();
1565    /// # let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nContent-Length: 0\r\n\r\n");
1566    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1567    /// assert_eq!(req.framing(), BodyFraming::None);
1568    /// assert_eq!(req.content_length(), Some(0));
1569    /// ```
1570    #[must_use]
1571    pub fn content_length(&self) -> Option<u64> {
1572        self.info.content_length
1573    }
1574
1575    /// The authority the request is for (`host [":" port]`), if known.
1576    ///
1577    /// This is the `Host` field, except for an absolute-form target
1578    /// (`GET http://example.com/ HTTP/1.1`), whose authority wins: RFC 9112
1579    /// section 3.2.2 requires a server to ignore `Host` then, so the two can
1580    /// never be read differently. The raw field stays available through
1581    /// `header("host")`. HTTP/1.1 requests always carry a valid `Host`;
1582    /// HTTP/1.0 requests may not, and an empty `Host` (a target with no
1583    /// authority) is reported as `Some("")`.
1584    ///
1585    /// # Examples
1586    ///
1587    /// ```
1588    /// # use http_net::{ServerConn, ServerEvent};
1589    /// # let mut conn = ServerConn::new();
1590    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n");
1591    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1592    /// assert_eq!(req.host(), Some("127.0.0.1:8080"));
1593    ///
1594    /// # let mut conn = ServerConn::new();
1595    /// # let _ = conn.feed(b"GET http://a.test/x HTTP/1.1\r\nHost: b.test\r\n\r\n");
1596    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1597    /// assert_eq!(req.host(), Some("a.test"));
1598    /// assert_eq!(req.header("host"), Some(&b"b.test"[..]));
1599    /// ```
1600    #[must_use]
1601    pub fn host(&self) -> Option<&'a str> {
1602        self.info
1603            .authority
1604            .or(self.info.host)
1605            .and_then(|s| core::str::from_utf8(s.get(self.head)).ok())
1606    }
1607
1608    /// Whether the client sent `Expect: 100-continue` and is waiting for a
1609    /// `100 Continue` before sending the body. Only HTTP/1.1 requests that
1610    /// have a body report it (RFC 9110 section 10.1.1).
1611    ///
1612    /// Answer it before reading the body: either
1613    /// [`ServerConn::send_continue`](crate::ServerConn::send_continue), or a
1614    /// final response straight away (which closes the connection afterwards,
1615    /// since the body was not read). The blocking `Server` sends
1616    /// `100 Continue` itself.
1617    ///
1618    /// # Examples
1619    ///
1620    /// ```
1621    /// # use http_net::{ServerConn, ServerEvent};
1622    /// # let mut conn = ServerConn::new();
1623    /// # let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nExpect: 100-continue\r\nContent-Length: 9\r\n\r\n");
1624    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1625    /// assert!(req.expects_continue());
1626    /// ```
1627    #[must_use]
1628    pub fn expects_continue(&self) -> bool {
1629        self.info.expect_continue
1630    }
1631
1632    /// How the request body is delimited.
1633    ///
1634    /// # Examples
1635    ///
1636    /// ```
1637    /// # use http_net::{BodyFraming, ServerConn, ServerEvent};
1638    /// # let mut conn = ServerConn::new();
1639    /// # let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n");
1640    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1641    /// assert_eq!(req.framing(), BodyFraming::Chunked);
1642    /// ```
1643    #[must_use]
1644    pub fn framing(&self) -> BodyFraming {
1645        self.info.framing
1646    }
1647
1648    /// Whether the client allows the connection to stay open after this
1649    /// exchange (HTTP/1.1 unless `Connection: close`; HTTP/1.0 only with
1650    /// `Connection: keep-alive`).
1651    ///
1652    /// # Examples
1653    ///
1654    /// ```
1655    /// # use http_net::{ServerConn, ServerEvent};
1656    /// # let mut conn = ServerConn::new();
1657    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nConnection: close\r\n\r\n");
1658    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1659    /// assert!(!req.keep_alive());
1660    /// ```
1661    #[must_use]
1662    pub fn keep_alive(&self) -> bool {
1663        self.info.keep_alive
1664    }
1665
1666    /// Whether this is an HTTP/1.1 request to switch protocols: `Connection`
1667    /// lists `upgrade` and an `Upgrade` field offers at least one protocol
1668    /// other than `h2c` (read the offers with
1669    /// [`upgrade_protocols`](Self::upgrade_protocols)). Answer
1670    /// with [`Response::switching_protocols`](crate::Response::switching_protocols)
1671    /// naming an offered protocol to hand the connection over.
1672    ///
1673    /// `h2c` is never an offer: RFC 9113 section 3.1 deprecates the
1674    /// HTTP/2 upgrade, and a proxy that forwards it blindly is open to h2c
1675    /// smuggling. A request offering only `h2c` is served as HTTP/1.1.
1676    ///
1677    /// # Examples
1678    ///
1679    /// ```
1680    /// # use http_net::{ServerConn, ServerEvent};
1681    /// # let mut conn = ServerConn::new();
1682    /// # let _ = conn.feed(b"GET /ws HTTP/1.1\r\nHost: a\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n");
1683    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1684    /// assert!(req.is_upgrade());
1685    /// assert_eq!(req.header("upgrade"), Some(&b"websocket"[..]));
1686    ///
1687    /// # let mut conn = ServerConn::new();
1688    /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: Upgrade, HTTP2-Settings\r\nUpgrade: h2c\r\nHTTP2-Settings: AAMAAABkAAQAoAAA\r\n\r\n");
1689    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1690    /// assert!(!req.is_upgrade());
1691    /// ```
1692    #[must_use]
1693    pub fn is_upgrade(&self) -> bool {
1694        self.info.upgrade
1695    }
1696
1697    /// Whether the request carries an expectation other than
1698    /// `100-continue` (any `Expect` list element, any HTTP version), which
1699    /// a server may answer with `417 Expectation Failed` (RFC 9110 section
1700    /// 10.1.1). The core never answers it by itself; the blocking server
1701    /// does. The expectation never changes how the body is framed.
1702    ///
1703    /// # Examples
1704    ///
1705    /// ```
1706    /// # use http_net::{ServerConn, ServerEvent};
1707    /// # let mut conn = ServerConn::new();
1708    /// # let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nExpect: 100-continue, x-fast\r\nContent-Length: 1\r\n\r\n");
1709    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1710    /// assert!(req.expects_continue());
1711    /// assert!(req.has_unknown_expectation());
1712    /// ```
1713    #[must_use]
1714    pub fn has_unknown_expectation(&self) -> bool {
1715        self.info.unknown_expectation
1716    }
1717
1718    /// The protocols the request's `Upgrade` field offers, in order, as
1719    /// product tokens (`websocket`, `foo/2`), across every `Upgrade` line;
1720    /// `h2c` is left out (it is never an offer). Empty unless
1721    /// [`is_upgrade`](Self::is_upgrade).
1722    ///
1723    /// # Examples
1724    ///
1725    /// ```
1726    /// # use http_net::{ServerConn, ServerEvent};
1727    /// # let mut conn = ServerConn::new();
1728    /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: upgrade\r\nUpgrade: h2c, websocket/13, irc\r\n\r\n");
1729    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1730    /// let offered: Vec<&[u8]> = req.upgrade_protocols().collect();
1731    /// assert_eq!(offered, [&b"websocket/13"[..], b"irc"]);
1732    /// ```
1733    #[must_use]
1734    pub fn upgrade_protocols(&self) -> ListElements<'a, 'static> {
1735        let mut list = list_values(self.head, self.fields, "upgrade");
1736        list.skip_h2c = true;
1737        if !self.info.upgrade {
1738            list.fields = [].iter();
1739        }
1740        list
1741    }
1742
1743    /// The options the request's `Connection` field lists, across every
1744    /// `Connection` line, in order (`close`, `keep-alive`, `upgrade`, and the
1745    /// names of fields that are hop-by-hop for this message). Compare them
1746    /// ASCII case-insensitively. A proxy passes them to
1747    /// [`is_hop_by_hop`](crate::is_hop_by_hop).
1748    ///
1749    /// # Examples
1750    ///
1751    /// ```
1752    /// # use http_net::{ServerConn, ServerEvent};
1753    /// # let mut conn = ServerConn::new();
1754    /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive, X-Trace\r\n\r\n");
1755    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1756    /// let options: Vec<&[u8]> = req.connection_options().collect();
1757    /// assert_eq!(options, [&b"keep-alive"[..], b"X-Trace"]);
1758    /// ```
1759    #[must_use]
1760    pub fn connection_options(&self) -> ListElements<'a, 'static> {
1761        list_values(self.head, self.fields, "connection")
1762    }
1763
1764    /// The elements of a comma-separated list field (`#rule`, RFC 9110
1765    /// section 5.6.1) across every line with this name, in order, trimmed
1766    /// of whitespace, empty elements skipped. A comma inside a quoted
1767    /// string does not split an element.
1768    ///
1769    /// # Examples
1770    ///
1771    /// ```
1772    /// # use http_net::{ServerConn, ServerEvent};
1773    /// # let mut conn = ServerConn::new();
1774    /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nAccept: text/html, ,\r\nAccept: x/y;q=\"0.5,1\"\r\n\r\n");
1775    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1776    /// let accept: Vec<&[u8]> = req.header_list("accept").collect();
1777    /// assert_eq!(accept, [&b"text/html"[..], b"x/y;q=\"0.5,1\""]);
1778    /// ```
1779    #[must_use]
1780    pub fn header_list<'n>(&self, name: &'n str) -> ListElements<'a, 'n> {
1781        list_values(self.head, self.fields, name)
1782    }
1783
1784    /// Whether the request's `Upgrade` field offers `protocol` (see
1785    /// [`Response::switching_protocols`](crate::Response::switching_protocols)).
1786    pub(crate) fn offers(&self, protocol: &[u8]) -> bool {
1787        self.info.upgrade
1788            && self
1789                .header_all("upgrade")
1790                .any(|v| list_elements(v).any(|e| protocol_matches(protocol, e)))
1791    }
1792}
1793
1794/// Shows method, target, version, fields, and framing; the query and the
1795/// values of credential fields are replaced by `<redacted N bytes>`.
1796impl fmt::Debug for RequestHead<'_> {
1797    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1798        f.debug_struct("RequestHead")
1799            .field("method", &self.method_str())
1800            .field("target", &Target(self.target()))
1801            .field("version", &self.version())
1802            .field("headers", &self.headers())
1803            .field("framing", &self.framing())
1804            .finish()
1805    }
1806}
1807
1808/// A parsed response head, borrowed from the client connection's buffer.
1809///
1810/// # Examples
1811///
1812/// ```
1813/// use http_net::{ClientConn, ClientEvent, Request};
1814///
1815/// let mut conn = ClientConn::new();
1816/// let mut out = Vec::new();
1817/// conn.send_request(&Request::get("/").header("host", "a"), &mut out).unwrap();
1818/// let _ = conn.feed(b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
1819/// let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1820/// assert_eq!(resp.status(), 404);
1821/// assert_eq!(resp.reason(), "Not Found");
1822/// ```
1823#[derive(Clone, Copy)]
1824pub struct ResponseHead<'a> {
1825    head: &'a [u8],
1826    fields: &'a [Field],
1827    info: &'a ResponseInfo,
1828}
1829
1830impl<'a> ResponseHead<'a> {
1831    pub(crate) const fn new(head: &'a [u8], fields: &'a [Field], info: &'a ResponseInfo) -> Self {
1832        Self { head, fields, info }
1833    }
1834
1835    /// As [`RequestHead::parts`], for a response.
1836    pub(crate) const fn parts(&self) -> (&'a [u8], &'a [Field], &'a ResponseInfo) {
1837        (self.head, self.fields, self.info)
1838    }
1839
1840    /// The status code (`100..=599`).
1841    ///
1842    /// # Examples
1843    ///
1844    /// ```
1845    /// # use http_net::{ClientConn, ClientEvent, Request};
1846    /// # let mut conn = ClientConn::new();
1847    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1848    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1849    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1850    /// assert_eq!(resp.status(), 200);
1851    /// ```
1852    #[must_use]
1853    pub fn status(&self) -> u16 {
1854        self.info.status
1855    }
1856
1857    /// The reason phrase, if it is UTF-8 (it carries no meaning; RFC 9112
1858    /// tells clients to ignore it). Empty for a status line without one,
1859    /// including `HTTP/1.1 200` with no space after the code.
1860    ///
1861    /// # Examples
1862    ///
1863    /// ```
1864    /// # use http_net::{ClientConn, ClientEvent, Request};
1865    /// # let mut conn = ClientConn::new();
1866    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1867    /// # let _ = conn.feed(b"HTTP/1.1 200 \r\nContent-Length: 0\r\n\r\n");
1868    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1869    /// assert_eq!(resp.reason(), "");
1870    /// ```
1871    #[must_use]
1872    pub fn reason(&self) -> &'a str {
1873        core::str::from_utf8(self.info.reason.get(self.head)).unwrap_or("")
1874    }
1875
1876    /// The protocol version.
1877    ///
1878    /// # Examples
1879    ///
1880    /// ```
1881    /// # use http_net::{ClientConn, ClientEvent, Request, Version};
1882    /// # let mut conn = ClientConn::new();
1883    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1884    /// # let _ = conn.feed(b"HTTP/1.0 200 OK\r\n\r\n");
1885    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1886    /// assert_eq!(resp.version(), Version::Http10);
1887    /// ```
1888    #[must_use]
1889    pub fn version(&self) -> Version {
1890        self.info.version
1891    }
1892
1893    /// All fields in arrival order.
1894    ///
1895    /// # Examples
1896    ///
1897    /// ```
1898    /// # use http_net::{ClientConn, ClientEvent, Request};
1899    /// # let mut conn = ClientConn::new();
1900    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1901    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\nX: y\r\n\r\n");
1902    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1903    /// assert_eq!(resp.headers().count(), 2);
1904    /// ```
1905    #[must_use]
1906    pub fn headers(&self) -> Headers<'a> {
1907        Headers {
1908            head: self.head,
1909            fields: self.fields.iter(),
1910        }
1911    }
1912
1913    /// The value of the first field named `name` (ASCII case-insensitive).
1914    ///
1915    /// # Examples
1916    ///
1917    /// ```
1918    /// # use http_net::{ClientConn, ClientEvent, Request};
1919    /// # let mut conn = ClientConn::new();
1920    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1921    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n");
1922    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1923    /// assert_eq!(resp.header("content-type"), Some(&b"text/plain"[..]));
1924    /// ```
1925    #[must_use]
1926    pub fn header(&self, name: &str) -> Option<&'a [u8]> {
1927        find_header(self.head, self.fields, name)
1928    }
1929
1930    /// Like [`header`](Self::header), but only when the value is UTF-8.
1931    ///
1932    /// # Examples
1933    ///
1934    /// ```
1935    /// # use http_net::{ClientConn, ClientEvent, Request};
1936    /// # let mut conn = ClientConn::new();
1937    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1938    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nServer: x\r\nContent-Length: 0\r\n\r\n");
1939    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1940    /// assert_eq!(resp.header_str("server"), Some("x"));
1941    /// ```
1942    #[must_use]
1943    pub fn header_str(&self, name: &str) -> Option<&'a str> {
1944        self.header(name).and_then(|v| core::str::from_utf8(v).ok())
1945    }
1946
1947    /// The values of every field named `name`, in arrival order. Each
1948    /// `Set-Cookie` is its own field (they are never comma-joined), so
1949    /// this is how a client reads all of them.
1950    ///
1951    /// # Examples
1952    ///
1953    /// ```
1954    /// # use http_net::{ClientConn, ClientEvent, Request};
1955    /// # let mut conn = ClientConn::new();
1956    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1957    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nSet-Cookie: a=1\r\nSet-Cookie: b=2; Path=/\r\nContent-Length: 0\r\n\r\n");
1958    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1959    /// let cookies: Vec<&[u8]> = resp.header_all("set-cookie").collect();
1960    /// assert_eq!(cookies, [&b"a=1"[..], &b"b=2; Path=/"[..]]);
1961    /// ```
1962    #[must_use]
1963    pub fn header_all<'n>(&self, name: &'n str) -> HeaderValues<'a, 'n> {
1964        header_values(self.head, self.fields, name)
1965    }
1966
1967    /// The declared `Content-Length`, if the response has one, whatever the
1968    /// framing rules made of it (a `HEAD` response's length is reported
1969    /// here while [`framing`](Self::framing) is `None`).
1970    ///
1971    /// # Examples
1972    ///
1973    /// ```
1974    /// # use http_net::{BodyFraming, ClientConn, ClientEvent, Request};
1975    /// # let mut conn = ClientConn::new();
1976    /// # conn.send_request(&Request::head("/").header("host", "a"), &mut Vec::new()).unwrap();
1977    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 1234\r\n\r\n");
1978    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1979    /// assert_eq!(resp.framing(), BodyFraming::None);
1980    /// assert_eq!(resp.content_length(), Some(1234));
1981    /// ```
1982    #[must_use]
1983    pub fn content_length(&self) -> Option<u64> {
1984        self.info.content_length
1985    }
1986
1987    /// The elements of a list field across every line with this name (see
1988    /// [`RequestHead::header_list`]).
1989    ///
1990    /// # Examples
1991    ///
1992    /// ```
1993    /// # use http_net::{ClientConn, ClientEvent, Request};
1994    /// # let mut conn = ClientConn::new();
1995    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1996    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nVary: accept\r\nVary: origin, cookie\r\nContent-Length: 0\r\n\r\n");
1997    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1998    /// assert_eq!(resp.header_list("vary").count(), 3);
1999    /// ```
2000    #[must_use]
2001    pub fn header_list<'n>(&self, name: &'n str) -> ListElements<'a, 'n> {
2002        list_values(self.head, self.fields, name)
2003    }
2004
2005    /// Whether this is an interim (1xx) response head, as reported by
2006    /// [`ClientEvent::Informational`](crate::ClientEvent::Informational).
2007    ///
2008    /// # Examples
2009    ///
2010    /// ```
2011    /// # use http_net::{ClientConn, ClientEvent, Request};
2012    /// # let mut conn = ClientConn::new();
2013    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
2014    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
2015    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
2016    /// assert!(!resp.is_informational());
2017    /// ```
2018    #[must_use]
2019    pub fn is_informational(&self) -> bool {
2020        (100..200).contains(&self.info.status)
2021    }
2022
2023    /// How the response body is delimited (accounts for `HEAD` requests and
2024    /// bodiless status codes).
2025    ///
2026    /// # Examples
2027    ///
2028    /// ```
2029    /// # use http_net::{BodyFraming, ClientConn, ClientEvent, Request};
2030    /// # let mut conn = ClientConn::new();
2031    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
2032    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\n\r\n");
2033    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
2034    /// assert_eq!(resp.framing(), BodyFraming::UntilClose);
2035    /// ```
2036    #[must_use]
2037    pub fn framing(&self) -> BodyFraming {
2038        self.info.framing
2039    }
2040
2041    /// Whether the connection can carry another request after this response.
2042    ///
2043    /// # Examples
2044    ///
2045    /// ```
2046    /// # use http_net::{ClientConn, ClientEvent, Request};
2047    /// # let mut conn = ClientConn::new();
2048    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
2049    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
2050    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
2051    /// assert!(resp.keep_alive());
2052    /// ```
2053    #[must_use]
2054    pub fn keep_alive(&self) -> bool {
2055        self.info.keep_alive
2056    }
2057}
2058
2059/// Shows status, reason, version, fields, and framing; the values of
2060/// credential fields (`set-cookie` above all) are replaced by
2061/// `<redacted N bytes>`.
2062impl fmt::Debug for ResponseHead<'_> {
2063    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2064        f.debug_struct("ResponseHead")
2065            .field("status", &self.status())
2066            .field("reason", &self.reason())
2067            .field("version", &self.version())
2068            .field("headers", &self.headers())
2069            .field("framing", &self.framing())
2070            .finish()
2071    }
2072}
2073
2074#[cfg(test)]
2075mod tests {
2076    use alloc::vec::Vec;
2077
2078    use super::*;
2079
2080    /// Lines built from the bytes that decide field parsing, at random.
2081    fn random_lines(count: usize) -> Vec<Vec<u8>> {
2082        const BYTES: &[u8] = b"aZ09-!~:: \t\r\n\x00\x7f\x80\xff\"(,";
2083        let mut state = 0x2545_f491_4f6c_dd1du64;
2084        let mut next = move || {
2085            state ^= state << 13;
2086            state ^= state >> 7;
2087            state ^= state << 17;
2088            state
2089        };
2090        // Mostly the shape a field line has (a name, a colon, a value), with
2091        // the deciding bytes mixed in now and then, so lines land on both
2092        // sides of what the fast path accepts.
2093        let mut pick = move |plain: &[u8]| {
2094            if next() % 12 == 0 {
2095                BYTES[(next() % BYTES.len() as u64) as usize]
2096            } else {
2097                plain[(next() % plain.len() as u64) as usize]
2098            }
2099        };
2100        (0..count)
2101            .map(|i| {
2102                let mut line = Vec::new();
2103                for _ in 0..(i % 9) {
2104                    line.push(pick(b"abcXYZ019-_.!~"));
2105                }
2106                line.push(pick(b":"));
2107                for _ in 0..(i % 23) {
2108                    line.push(pick(b"  abc XYZ 019 ,;=/\"()[]{}"));
2109                }
2110                if i % 5 != 0 {
2111                    line.extend_from_slice(b"\r\n");
2112                }
2113                line
2114            })
2115            .collect()
2116    }
2117
2118    #[test]
2119    fn test_fast_field_agrees_with_the_general_path() {
2120        let mut fast = 0;
2121        for line in random_lines(300_000).into_iter().chain([
2122            b"Host: a\r\n".to_vec(),
2123            b"X:\r\n".to_vec(),
2124            b"X:   \r\n".to_vec(),
2125            b"X:  a  b  \r\n".to_vec(),
2126            b"X: a\tb\r\n".to_vec(),
2127            b"X: a\r".to_vec(),
2128            b"X: a\n".to_vec(),
2129            b" X: a\r\n".to_vec(),
2130            b"X : a\r\n".to_vec(),
2131            b"X: \x80\r\n".to_vec(),
2132            b"X: a\rb\r\n".to_vec(),
2133        ]) {
2134            let Some((field, next)) = fast_field(&line, 0) else {
2135                continue;
2136            };
2137            fast += 1;
2138            // The general path on the same line: the LF it finds, then the
2139            // field it parses.
2140            let lf = find_byte(b'\n', &line).expect("an accepted line has an LF");
2141            assert_eq!(next, lf + 1, "{line:?}");
2142            assert_eq!(line[lf - 1], b'\r', "{line:?}");
2143            assert_eq!(parse_field(&line[..lf - 1], 0), Ok(field), "{line:?}");
2144        }
2145        assert!(fast > 1_000, "the fast path accepted only {fast} lines");
2146    }
2147
2148    #[test]
2149    fn test_scan_with_and_without_the_fast_path_agree_at_every_split() {
2150        // Whole input takes the fast path; one byte at a time cannot (a
2151        // line is never complete when its search starts), so it exercises
2152        // the general path. Both must report the same fields and errors.
2153        let heads: [&[u8]; 6] = [
2154            b"GET / HTTP/1.1\r\nHost: a\r\nX:  b  \r\nY:\r\n\r\n",
2155            b"GET / HTTP/1.1\r\nHost: a\r\nX: a\tb\r\n\r\n",
2156            b"GET / HTTP/1.1\r\nHost: a\r\nX: a\rb\r\n\r\n",
2157            b"GET / HTTP/1.1\r\nHost: a\r\nX : b\r\n\r\n",
2158            b"GET / HTTP/1.1\r\nHost: a\r\n X: b\r\n\r\n",
2159            b"GET / HTTP/1.1\r\nHost: a\r\nX: \x80\x81\r\n\r\n",
2160        ];
2161        let fields = |s: &HeadScanner| {
2162            s.fields
2163                .iter()
2164                .map(|f| (f.name, f.value))
2165                .collect::<Vec<_>>()
2166        };
2167        for head in heads {
2168            let mut whole = HeadScanner::new();
2169            let whole_result = whole.advance(head, &Limits::new(), HeadKind::Request, true);
2170            let mut split = HeadScanner::new();
2171            let mut split_result = Ok(Scan::Partial);
2172            for end in 1..=head.len() {
2173                split_result = split.advance(&head[..end], &Limits::new(), HeadKind::Request, true);
2174                if !matches!(split_result, Ok(Scan::Partial)) {
2175                    break;
2176                }
2177            }
2178            assert_eq!(whole_result, split_result, "{head:?}");
2179            assert_eq!(fields(&whole), fields(&split), "{head:?}");
2180        }
2181    }
2182
2183    fn scan(msg: &[u8], kind: HeadKind) -> Result<(HeadScanner, usize), HttpError> {
2184        let mut s = HeadScanner::new();
2185        match s.advance(msg, &Limits::new(), kind, true)? {
2186            Scan::Done(n) => Ok((s, n)),
2187            Scan::Partial => Err(HttpError::UnexpectedEof),
2188        }
2189    }
2190
2191    #[test]
2192    fn test_scanner_resumes_without_rescanning() {
2193        let msg = b"GET / HTTP/1.1\r\nHost: a\r\n\r\n";
2194        let mut s = HeadScanner::new();
2195        for end in 1..msg.len() {
2196            assert!(matches!(
2197                s.advance(&msg[..end], &Limits::new(), HeadKind::Request, true),
2198                Ok(Scan::Partial)
2199            ));
2200        }
2201        assert!(matches!(
2202            s.advance(msg, &Limits::new(), HeadKind::Request, true),
2203            Ok(Scan::Done(n)) if n == msg.len()
2204        ));
2205        assert_eq!(s.fields.len(), 1);
2206    }
2207
2208    #[test]
2209    fn test_scanner_rejects_line_shapes() {
2210        let cases: &[(&[u8], HttpError)] = &[
2211            (b"GET / HTTP/1.1\nHost: a\r\n\r\n", HttpError::BareLf),
2212            (b"GET / HTTP/1.1\r\n Host: a\r\n\r\n", HttpError::ObsFold),
2213            (
2214                b"GET / HTTP/1.1\r\nHost : a\r\n\r\n",
2215                HttpError::WhitespaceBeforeColon,
2216            ),
2217            (
2218                b"GET / HTTP/1.1\r\nHost\r\n\r\n",
2219                HttpError::InvalidHeaderName,
2220            ),
2221            (
2222                b"GET / HTTP/1.1\r\n: a\r\n\r\n",
2223                HttpError::InvalidHeaderName,
2224            ),
2225            (b"GET / HTTP/1.1\r\nHo\rst: a\r\n\r\n", HttpError::BareCr),
2226            (b"GET / HTTP/1.1\r\nHost: a\rb\r\n\r\n", HttpError::BareCr),
2227            (b"GET /\r HTTP/1.1\r\n\r\n", HttpError::BareCr),
2228            (
2229                b"GET / HTTP/1.1\r\nHost: a\x00\r\n\r\n",
2230                HttpError::InvalidHeaderValue,
2231            ),
2232        ];
2233        for (msg, err) in cases {
2234            assert_eq!(scan(msg, HeadKind::Request).err(), Some(*err), "{msg:?}");
2235        }
2236    }
2237
2238    #[test]
2239    fn test_scanner_skips_leading_empty_lines_for_requests_only() {
2240        assert!(scan(b"\r\n\r\nGET / HTTP/1.1\r\n\r\n", HeadKind::Request).is_ok());
2241        assert_eq!(
2242            scan(b"\r\nHTTP/1.1 200 OK\r\n\r\n", HeadKind::Response).err(),
2243            Some(HttpError::InvalidStartLine)
2244        );
2245    }
2246
2247    #[test]
2248    fn test_scanner_enforces_limits_at_boundaries() {
2249        let limits = Limits::new().with_max_start_line(16);
2250        // "GET / HTTP/1.1\r\n" is exactly 16 bytes.
2251        let mut s = HeadScanner::new();
2252        assert!(
2253            s.advance(b"GET / HTTP/1.1\r\n\r\n", &limits, HeadKind::Request, true)
2254                .is_ok()
2255        );
2256        let mut s = HeadScanner::new();
2257        assert_eq!(
2258            s.advance(b"GET /a HTTP/1.1\r\n\r\n", &limits, HeadKind::Request, true)
2259                .err(),
2260            Some(HttpError::StartLineTooLong)
2261        );
2262        // Partial input already at the budget fails without waiting for LF.
2263        let mut s = HeadScanner::new();
2264        assert_eq!(
2265            s.advance(b"GET /aaaaaaaaaaaa", &limits, HeadKind::Request, true)
2266                .err(),
2267            Some(HttpError::StartLineTooLong)
2268        );
2269
2270        let limits = Limits::new().with_max_headers(1);
2271        let mut s = HeadScanner::new();
2272        assert_eq!(
2273            s.advance(
2274                b"GET / HTTP/1.1\r\nA: 1\r\nB: 2\r\n\r\n",
2275                &limits,
2276                HeadKind::Request,
2277                true
2278            )
2279            .err(),
2280            Some(HttpError::TooManyHeaders)
2281        );
2282
2283        // "A: 1\r\n" is 6 bytes; with 8 the final CRLF still fits.
2284        let limits = Limits::new().with_max_header_bytes(8);
2285        let mut s = HeadScanner::new();
2286        assert!(
2287            s.advance(
2288                b"GET / HTTP/1.1\r\nA: 1\r\n\r\n",
2289                &limits,
2290                HeadKind::Request,
2291                true
2292            )
2293            .is_ok()
2294        );
2295        let mut s = HeadScanner::new();
2296        assert_eq!(
2297            s.advance(
2298                b"GET / HTTP/1.1\r\nA: 12\r\nB: 1\r\n\r\n",
2299                &limits,
2300                HeadKind::Request,
2301                true
2302            )
2303            .err(),
2304            Some(HttpError::HeadersTooLarge)
2305        );
2306    }
2307
2308    fn response(line: &[u8]) -> Result<ResponseInfo, HttpError> {
2309        let mut msg = line.to_vec();
2310        msg.extend_from_slice(b"\r\nContent-Length: 0\r\n\r\n");
2311        let (s, _) = scan(&msg, HeadKind::Response)?;
2312        interpret_response(
2313            &msg,
2314            s.start_line(),
2315            &s.fields,
2316            &Limits::new(),
2317            Asked {
2318                head: false,
2319                connect: false,
2320            },
2321        )
2322    }
2323
2324    #[test]
2325    fn test_status_line_without_space_after_code_is_accepted() {
2326        let info = response(b"HTTP/1.1 200").unwrap();
2327        assert_eq!(info.status, 200);
2328        assert_eq!(info.reason, Span::new(12, 12));
2329        assert_eq!(response(b"HTTP/1.1 200 ").unwrap().status, 200);
2330        assert_eq!(response(b"HTTP/1.1 204 No Content").unwrap().status, 204);
2331        assert_eq!(
2332            response(b"HTTP/1.1 20").err(),
2333            Some(HttpError::InvalidStartLine)
2334        );
2335        assert_eq!(
2336            response(b"HTTP/1.1 2000").err(),
2337            Some(HttpError::InvalidStartLine)
2338        );
2339        assert_eq!(
2340            response(b"HTTP/1.1200 OK").err(),
2341            Some(HttpError::InvalidStartLine)
2342        );
2343        assert_eq!(
2344            response(b"HTTP/1.1 600").err(),
2345            Some(HttpError::InvalidStatus)
2346        );
2347    }
2348
2349    #[test]
2350    fn test_protocol_matching_rules() {
2351        assert!(protocol_matches(b"websocket", b"websocket"));
2352        assert!(protocol_matches(b"WebSocket", b"websocket"));
2353        assert!(protocol_matches(b"websocket", b"websocket/13"));
2354        assert!(protocol_matches(b"foo/2", b"FOO/2"));
2355        assert!(!protocol_matches(b"foo/2", b"foo/3"));
2356        assert!(!protocol_matches(b"foo/2", b"foo"));
2357        assert!(!protocol_matches(b"ws", b"websocket"));
2358        assert!(!protocol_matches(b"h2c", b"h2c"));
2359        assert!(!protocol_matches(b"H2C", b"h2c"));
2360        assert!(is_h2c(b"h2c/1") && is_h2c(b"H2c") && !is_h2c(b"h2"));
2361    }
2362
2363    #[test]
2364    fn test_authority_targets_refuse_empty_host_and_bad_escapes() {
2365        assert!(check_target(Method::Connect, b"a%41:443").is_ok());
2366        assert!(check_target(Method::Connect, b"a%4:443").is_err());
2367        assert!(check_target(Method::Get, b"http://a%zz/").is_err());
2368        assert!(check_target(Method::Get, b"http://a%41b/").is_ok());
2369        assert!(check_target(Method::Get, b"ftp://h/").is_ok());
2370    }
2371
2372    #[test]
2373    fn test_versions() {
2374        assert_eq!(parse_version(b"HTTP/1.1"), Ok(Version::Http11));
2375        assert_eq!(parse_version(b"HTTP/1.0"), Ok(Version::Http10));
2376        assert_eq!(parse_version(b"HTTP/1.9"), Ok(Version::Http11));
2377        assert_eq!(
2378            parse_version(b"HTTP/2.0"),
2379            Err(HttpError::UnsupportedVersion)
2380        );
2381        assert_eq!(
2382            parse_version(b"HTTP/0.9"),
2383            Err(HttpError::UnsupportedVersion)
2384        );
2385        assert_eq!(parse_version(b"http/1.1"), Err(HttpError::InvalidVersion));
2386        assert_eq!(parse_version(b"HTTP/1.10"), Err(HttpError::InvalidVersion));
2387        assert_eq!(parse_version(b"HTTP/1"), Err(HttpError::InvalidVersion));
2388    }
2389
2390    #[test]
2391    fn test_target_forms_follow_method() {
2392        assert!(check_target(Method::Get, b"/").is_ok());
2393        assert!(check_target(Method::Options, b"*").is_ok());
2394        assert!(check_target(Method::Get, b"*").is_err());
2395        assert!(check_target(Method::Connect, b"example.com:443").is_ok());
2396        assert!(check_target(Method::Connect, b"[::1]:443").is_ok());
2397        assert!(check_target(Method::Connect, b"example.com").is_err());
2398        assert!(check_target(Method::Connect, b"/").is_err());
2399        assert!(check_target(Method::Get, b"http://example.com/a?b").is_ok());
2400        assert!(check_target(Method::Get, b"http://[::1]:80/").is_ok());
2401        assert!(check_target(Method::Get, b"http://x").is_ok());
2402        assert!(check_target(Method::Get, b"http://x?q").is_ok());
2403        assert!(check_target(Method::Get, b"http://u@x/").is_err());
2404        assert!(check_target(Method::Get, b"http:x").is_err());
2405        assert!(check_target(Method::Get, b"http://:80/").is_err());
2406        assert!(check_target(Method::Get, b"http://x/[a]").is_err());
2407        assert!(check_target(Method::Connect, b":443").is_err());
2408        assert!(check_target(Method::Get, b"1http://x").is_err());
2409        assert!(check_target(Method::Get, b"example.com").is_err());
2410        assert!(check_target(Method::Get, b"").is_err());
2411    }
2412}