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