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    scan::{
20        ListSplit, check_field_value, find_byte, is_host_value, is_ows, is_reason, is_target_chars,
21        is_tchar, is_token, list_elements, parse_decimal, printable_run, trim_ows,
22    },
23};
24
25/// A byte range of a message head: `start..end`, as offsets into
26/// [`RawHead::bytes`](crate::RawHead::bytes) (or into the input of a
27/// stateless parser).
28///
29/// Offsets are `u32` because 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
610/// Whether a `101` switches only to protocols the request offered: the
611/// response's `Upgrade` fields name at least one protocol, and every one of
612/// them matches an element of `offer` (the request's `Upgrade` value).
613/// Names compare ASCII case-insensitively; a bare name matches a versioned
614/// one either way (`websocket` and `websocket/13`).
615pub(crate) fn switches_to_offered(head: &[u8], fields: &[Field], offer: &[u8]) -> bool {
616    let mut named = false;
617    for field in fields {
618        if !field.name.get(head).eq_ignore_ascii_case(b"upgrade") {
619            continue;
620        }
621        for chosen in list_elements(field.value.get(head)) {
622            named = true;
623            let offered = list_elements(offer)
624                .any(|o| protocol_matches(chosen, o) || protocol_matches(o, chosen));
625            if !offered {
626                return false;
627            }
628        }
629    }
630    named
631}
632
633pub(crate) fn parse_version(v: &[u8]) -> Result<Version, HttpError> {
634    match v {
635        [b'H', b'T', b'T', b'P', b'/', major, b'.', minor]
636            if major.is_ascii_digit() && minor.is_ascii_digit() =>
637        {
638            match (major, minor) {
639                (b'1', b'0') => Ok(Version::Http10),
640                (b'1', _) => Ok(Version::Http11),
641                _ => Err(HttpError::UnsupportedVersion),
642            }
643        }
644        _ => Err(HttpError::InvalidVersion),
645    }
646}
647
648/// What the framing-relevant fields of a message say.
649#[derive(Default)]
650struct FieldFacts {
651    content_length: Option<u64>,
652    te_seen: bool,
653    te_codings: usize,
654    te_chunked: usize,
655    te_last_chunked: bool,
656    te_other: bool,
657    close: bool,
658    keep_alive: bool,
659    upgrade_token: bool,
660    upgrade_field: bool,
661    /// An `Upgrade` element other than `h2c`.
662    upgrade_offer: bool,
663    expect_continue: bool,
664    /// An `Expect` element other than `100-continue`.
665    expect_other: bool,
666    hosts: usize,
667    host: Option<Span>,
668}
669
670fn scan_fields(head: &[u8], fields: &[Field]) -> Result<FieldFacts, HttpError> {
671    let mut facts = FieldFacts::default();
672    // The lengths of the six names below: most fields are ruled out before
673    // any compare.
674    const LENGTHS: u32 = (1 << 4) | (1 << 6) | (1 << 7) | (1 << 10) | (1 << 14) | (1 << 17);
675    for field in fields {
676        let name = field.name.get(head);
677        if name.len() > 17 || LENGTHS & (1 << name.len()) == 0 {
678            continue;
679        }
680        let value = field.value.get(head);
681        if name.eq_ignore_ascii_case(b"content-length") {
682            if facts.content_length.is_some() {
683                return Err(HttpError::DuplicateContentLength);
684            }
685            facts.content_length =
686                Some(parse_decimal(value).ok_or(HttpError::InvalidContentLength)?);
687        } else if name.eq_ignore_ascii_case(b"transfer-encoding") {
688            facts.te_seen = true;
689            for element in list_elements(value) {
690                let (coding, params) = match find_byte(b';', element) {
691                    Some(i) => (trim_ows(&element[..i]), true),
692                    None => (element, false),
693                };
694                if !is_token(coding) {
695                    return Err(HttpError::InvalidTransferEncoding);
696                }
697                facts.te_codings += 1;
698                if coding.eq_ignore_ascii_case(b"chunked") {
699                    if params {
700                        return Err(HttpError::InvalidTransferEncoding);
701                    }
702                    facts.te_chunked += 1;
703                    facts.te_last_chunked = true;
704                } else {
705                    facts.te_other = true;
706                    facts.te_last_chunked = false;
707                }
708            }
709        } else if name.eq_ignore_ascii_case(b"connection") {
710            for token in list_elements(value) {
711                if token.eq_ignore_ascii_case(b"close") {
712                    facts.close = true;
713                } else if token.eq_ignore_ascii_case(b"keep-alive") {
714                    facts.keep_alive = true;
715                } else if token.eq_ignore_ascii_case(b"upgrade") {
716                    facts.upgrade_token = true;
717                }
718            }
719        } else if name.eq_ignore_ascii_case(b"upgrade") {
720            facts.upgrade_field |= !value.is_empty();
721            facts.upgrade_offer |= list_elements(value).any(|e| !is_h2c(e));
722        } else if name.eq_ignore_ascii_case(b"host") {
723            facts.hosts += 1;
724            facts.host = Some(field.value);
725        } else if name.eq_ignore_ascii_case(b"expect") {
726            // RFC 9110 section 10.1.1: the expectation is case-insensitive.
727            for e in list_elements(value) {
728                if e.eq_ignore_ascii_case(b"100-continue") {
729                    facts.expect_continue = true;
730                } else {
731                    facts.expect_other = true;
732                }
733            }
734        }
735    }
736    Ok(facts)
737}
738
739/// Applies RFC 9112 section 6 to the transfer-coding facts.
740fn transfer_framing(
741    facts: &FieldFacts,
742    version: Version,
743) -> Result<Option<BodyFraming>, HttpError> {
744    if !facts.te_seen {
745        return Ok(None);
746    }
747    if version == Version::Http10 {
748        return Err(HttpError::TransferEncodingInHttp10);
749    }
750    if facts.content_length.is_some() {
751        return Err(HttpError::ConflictingFraming);
752    }
753    if facts.te_codings == 0 || facts.te_chunked > 1 || !facts.te_last_chunked {
754        return Err(HttpError::InvalidTransferEncoding);
755    }
756    if facts.te_other {
757        return Err(HttpError::UnsupportedTransferEncoding);
758    }
759    Ok(Some(BodyFraming::Chunked))
760}
761
762/// Everything learned from a request head. Spans are offsets into the head
763/// bytes, so the facts stay valid when the bytes are copied.
764#[derive(Clone, Copy, Debug, PartialEq, Eq)]
765pub(crate) struct RequestInfo {
766    pub(crate) method: Method,
767    pub(crate) start_line: Span,
768    pub(crate) method_span: Span,
769    pub(crate) target: Span,
770    target_form: TargetForm,
771    pub(crate) version: Version,
772    pub(crate) framing: BodyFraming,
773    content_length: Option<u64>,
774    pub(crate) keep_alive: bool,
775    pub(crate) upgrade: bool,
776    pub(crate) expect_continue: bool,
777    unknown_expectation: bool,
778    pub(crate) host: Option<Span>,
779    /// The authority of an absolute-form target, which replaces `Host`.
780    pub(crate) authority: Option<Span>,
781    /// The path-and-query part of the target: the whole target except for
782    /// the absolute form, where it is what follows the authority.
783    pub(crate) origin: Span,
784}
785
786impl RequestInfo {
787    pub(crate) const EMPTY: Self = Self {
788        method: Method::Get,
789        start_line: Span { start: 0, end: 0 },
790        method_span: Span { start: 0, end: 0 },
791        target: Span { start: 0, end: 0 },
792        target_form: TargetForm::Origin,
793        version: Version::Http11,
794        framing: BodyFraming::None,
795        content_length: None,
796        keep_alive: false,
797        upgrade: false,
798        expect_continue: false,
799        unknown_expectation: false,
800        host: None,
801        authority: None,
802        origin: Span { start: 0, end: 0 },
803    };
804}
805
806/// Validates a request target against the forms its method allows.
807pub(crate) fn check_target(method: Method, target: &[u8]) -> Result<(), HttpError> {
808    let ok = match target.first() {
809        None => false,
810        Some(b'/') => method != Method::Connect && is_target_chars(target),
811        Some(b'*') if target.len() == 1 => method == Method::Options,
812        Some(_) if method == Method::Connect => {
813            // authority-form: host ":" port, with a non-empty host and port.
814            is_authority(target)
815                && target
816                    .iter()
817                    .rposition(|&b| b == b':')
818                    .is_some_and(|c| c + 1 < target.len() && !target[c..].contains(&b']'))
819        }
820        Some(_) => split_absolute_form(target).is_some(),
821    };
822    if ok {
823        Ok(())
824    } else {
825        Err(HttpError::InvalidTarget)
826    }
827}
828
829/// `host [":" port]` with a non-empty host: RFC 9110 section 4.2.1 makes an
830/// empty host in an `http` URI invalid.
831fn is_authority(s: &[u8]) -> bool {
832    !s.is_empty() && s[0] != b':' && is_host_value(s)
833}
834
835/// Splits an absolute-form target, `scheme "://" authority path-abempty
836/// [ "?" query ]`, returning the authority's range within it.
837///
838/// Only the hierarchical form with an authority is accepted: it is the form
839/// RFC 9112 section 3.2.2 describes (requests to proxies, and future
840/// requests to origin servers), and it is the only one that names the host
841/// the request is for. Userinfo is refused (RFC 9110 section 4.2.4 says to
842/// treat it as an error), as is an empty host.
843fn split_absolute_form(target: &[u8]) -> Option<(usize, usize)> {
844    let colon = find_byte(b':', target)?;
845    let scheme = &target[..colon];
846    let scheme_ok = scheme.first().is_some_and(u8::is_ascii_alphabetic)
847        && scheme
848            .iter()
849            .all(|&b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'));
850    if !scheme_ok || !target[colon..].starts_with(b"://") {
851        return None;
852    }
853    let auth_start = colon + 3;
854    let after = &target[auth_start..];
855    let auth_len = after
856        .iter()
857        .position(|&b| b == b'/' || b == b'?')
858        .unwrap_or(after.len());
859    let authority = &after[..auth_len];
860    let rest = &after[auth_len..];
861    (is_authority(authority) && is_target_chars(rest))
862        .then_some((auth_start, auth_start + auth_len))
863}
864
865pub(crate) fn interpret_request(
866    head: &[u8],
867    start: Span,
868    fields: &[Field],
869    limits: &Limits,
870) -> Result<RequestInfo, HttpError> {
871    let line = start.get(head);
872    let base = start.start as usize;
873    let sp1 = find_byte(b' ', line).ok_or(HttpError::InvalidStartLine)?;
874    let sp2 = line
875        .iter()
876        .rposition(|&b| b == b' ')
877        .ok_or(HttpError::InvalidStartLine)?;
878    if sp2 == sp1 {
879        return Err(HttpError::InvalidStartLine);
880    }
881    let method_bytes = &line[..sp1];
882    if !is_token(method_bytes) {
883        return Err(HttpError::InvalidMethod);
884    }
885    let version = parse_version(&line[sp2 + 1..])?;
886    let method = Method::from_bytes(method_bytes);
887    let target = &line[sp1 + 1..sp2];
888    check_target(method, target)?;
889    let target_start = base + sp1 + 1;
890    let target_span = Span::new(target_start, base + sp2);
891    let (target_form, authority, origin) = match target.first() {
892        Some(b'/') => (TargetForm::Origin, None, target_span),
893        Some(b'*') => (TargetForm::Asterisk, None, target_span),
894        _ if method == Method::Connect => (TargetForm::Authority, None, target_span),
895        _ => match split_absolute_form(target) {
896            Some((a, b)) => (
897                TargetForm::Absolute,
898                Some(Span::new(target_start + a, target_start + b)),
899                Span::new(target_start + b, base + sp2),
900            ),
901            None => return Err(HttpError::InvalidTarget),
902        },
903    };
904
905    let facts = scan_fields(head, fields)?;
906    let framing = match transfer_framing(&facts, version)? {
907        Some(f) => f,
908        None => match facts.content_length {
909            Some(n) if n > limits.max_body() => return Err(HttpError::BodyTooLarge),
910            Some(0) | None => BodyFraming::None,
911            Some(n) => BodyFraming::Length(n),
912        },
913    };
914    if facts.hosts > 1 {
915        return Err(HttpError::InvalidHost);
916    }
917    if let Some(host) = facts.host {
918        if !is_host_value(host.get(head)) {
919            return Err(HttpError::InvalidHost);
920        }
921    } else if version == Version::Http11 {
922        return Err(HttpError::MissingHost);
923    }
924    let keep_alive = match version {
925        Version::Http11 => !facts.close,
926        Version::Http10 => facts.keep_alive && !facts.close,
927    };
928    Ok(RequestInfo {
929        method,
930        start_line: start,
931        method_span: Span::new(base, base + sp1),
932        target: target_span,
933        target_form,
934        version,
935        framing,
936        content_length: facts.content_length,
937        keep_alive,
938        // RFC 9110 section 7.8: Upgrade in an HTTP/1.0 request is ignored.
939        // An offer of only `h2c` is no offer: the request is served as
940        // HTTP/1.1 (RFC 9113 section 3.1).
941        upgrade: version == Version::Http11 && facts.upgrade_token && facts.upgrade_offer,
942        // Reported for any version, so the caller can answer 417 (RFC 9110
943        // section 10.1.1 MAY); it never changes framing.
944        unknown_expectation: facts.expect_other,
945        // RFC 9110 section 10.1.1: ignored in HTTP/1.0, and meaningless
946        // without a body to wait for.
947        expect_continue: version == Version::Http11
948            && facts.expect_continue
949            && framing != BodyFraming::None,
950        host: facts.host,
951        authority,
952        origin,
953    })
954}
955
956/// Everything learned from a response head.
957#[derive(Clone, Copy, Debug, PartialEq, Eq)]
958pub(crate) struct ResponseInfo {
959    pub(crate) status: u16,
960    pub(crate) start_line: Span,
961    reason: Span,
962    pub(crate) version: Version,
963    pub(crate) framing: BodyFraming,
964    content_length: Option<u64>,
965    pub(crate) keep_alive: bool,
966    pub(crate) upgrade_field: bool,
967}
968
969impl ResponseInfo {
970    pub(crate) const EMPTY: Self = Self {
971        status: 0,
972        start_line: Span { start: 0, end: 0 },
973        reason: Span { start: 0, end: 0 },
974        version: Version::Http11,
975        framing: BodyFraming::None,
976        content_length: None,
977        keep_alive: false,
978        upgrade_field: false,
979    };
980}
981
982/// What the request asked for, which decides how its response is framed
983/// (RFC 9112 section 6.3): a response to `HEAD` has no body whatever its
984/// fields say, and a 2xx to `CONNECT` turns the connection into a tunnel.
985/// The input to [`parse_response_head`](crate::parse_response_head).
986///
987/// # Examples
988///
989/// ```
990/// use http_net::Asked;
991///
992/// let after_head = Asked { head: true, ..Asked::default() };
993/// assert!(after_head.head && !after_head.connect);
994/// ```
995#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
996pub struct Asked {
997    /// The request was `HEAD`.
998    pub head: bool,
999    /// The request was `CONNECT`.
1000    pub connect: bool,
1001}
1002
1003pub(crate) fn interpret_response(
1004    head: &[u8],
1005    start: Span,
1006    fields: &[Field],
1007    limits: &Limits,
1008    asked: Asked,
1009) -> Result<ResponseInfo, HttpError> {
1010    let line = start.get(head);
1011    let base = start.start as usize;
1012    // status-line = HTTP-version SP status-code SP [ reason-phrase ]
1013    // The SP after the code is required of senders, but some servers omit
1014    // it when the reason is empty (`HTTP/1.1 200`); accepting that cannot
1015    // change framing, so the client does (RFC 9112 section 4).
1016    if line.len() < 12 || line[8] != b' ' || (line.len() > 12 && line[12] != b' ') {
1017        return Err(HttpError::InvalidStartLine);
1018    }
1019    let version = parse_version(&line[..8])?;
1020    let code = &line[9..12];
1021    if !code.iter().all(u8::is_ascii_digit) {
1022        return Err(HttpError::InvalidStatus);
1023    }
1024    let status = code
1025        .iter()
1026        .fold(0u16, |acc, &d| acc * 10 + u16::from(d - b'0'));
1027    if !(100..=599).contains(&status) {
1028        return Err(HttpError::InvalidStatus);
1029    }
1030    let reason_start = line.len().min(13);
1031    let reason = &line[reason_start..];
1032    if !is_reason(reason) {
1033        return Err(HttpError::InvalidStartLine);
1034    }
1035
1036    let facts = scan_fields(head, fields)?;
1037    let bodiless = asked.head
1038        || (100..200).contains(&status)
1039        || status == 204
1040        || status == 304
1041        || (asked.connect && (200..300).contains(&status));
1042    let framing = if bodiless {
1043        BodyFraming::None
1044    } else {
1045        match transfer_framing(&facts, version)? {
1046            Some(f) => f,
1047            None => match facts.content_length {
1048                Some(n) if n > limits.max_body() => return Err(HttpError::BodyTooLarge),
1049                Some(0) => BodyFraming::None,
1050                Some(n) => BodyFraming::Length(n),
1051                None => BodyFraming::UntilClose,
1052            },
1053        }
1054    };
1055    let keep_alive = framing != BodyFraming::UntilClose
1056        && match version {
1057            Version::Http11 => !facts.close,
1058            Version::Http10 => facts.keep_alive && !facts.close,
1059        };
1060    Ok(ResponseInfo {
1061        status,
1062        start_line: start,
1063        reason: Span::new(base + reason_start, base + line.len()),
1064        version,
1065        framing,
1066        content_length: facts.content_length,
1067        keep_alive,
1068        upgrade_field: facts.upgrade_field,
1069    })
1070}
1071
1072/// Iterator over a head's fields as `(name, value)` pairs, in arrival order.
1073///
1074/// Names are returned as received (field names are case-insensitive; compare
1075/// with `eq_ignore_ascii_case`). Values have surrounding whitespace removed
1076/// and may contain any byte RFC 9110 allows, including `obs-text` above
1077/// 0x7F, so they are bytes rather than `str`.
1078///
1079/// # Examples
1080///
1081/// ```
1082/// use http_net::{ServerConn, ServerEvent};
1083///
1084/// let mut conn = ServerConn::new();
1085/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nX-One: 1\r\n\r\n");
1086/// if let ServerEvent::Request(req) = conn.poll().unwrap() {
1087///     let names: Vec<&str> = req.headers().map(|(n, _)| n).collect();
1088///     assert_eq!(names, ["Host", "X-One"]);
1089/// }
1090/// ```
1091#[derive(Clone)]
1092pub struct Headers<'a> {
1093    head: &'a [u8],
1094    fields: slice::Iter<'a, Field>,
1095}
1096
1097impl<'a> Headers<'a> {
1098    pub(crate) fn new(head: &'a [u8], fields: &'a [Field]) -> Self {
1099        Self {
1100            head,
1101            fields: fields.iter(),
1102        }
1103    }
1104}
1105
1106impl<'a> Iterator for Headers<'a> {
1107    type Item = (&'a str, &'a [u8]);
1108
1109    #[inline]
1110    fn next(&mut self) -> Option<Self::Item> {
1111        let field = self.fields.next()?;
1112        Some((
1113            core::str::from_utf8(field.name.get(self.head)).unwrap_or(""),
1114            field.value.get(self.head),
1115        ))
1116    }
1117
1118    #[inline]
1119    fn size_hint(&self) -> (usize, Option<usize>) {
1120        self.fields.size_hint()
1121    }
1122}
1123
1124impl ExactSizeIterator for Headers<'_> {}
1125
1126/// Shows the fields as `(name, value)` pairs; the values of credential
1127/// fields (`authorization`, `proxy-authorization`, `cookie`, `set-cookie`)
1128/// are replaced by `<redacted N bytes>`.
1129impl fmt::Debug for Headers<'_> {
1130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1131        let head = self.head;
1132        f.debug_list()
1133            .entries(self.fields.clone().map(|field| {
1134                let name = field.name.get(head);
1135                (
1136                    FieldName(name),
1137                    FieldValue {
1138                        name,
1139                        value: field.value.get(head),
1140                    },
1141                )
1142            }))
1143            .finish()
1144    }
1145}
1146
1147/// Iterator over the values of every field with one name, in arrival
1148/// order: what [`RequestHead::header_all`] and
1149/// [`ResponseHead::header_all`] return. Each `Set-Cookie`, for example, is
1150/// its own field and its own item; nothing is comma-joined.
1151///
1152/// # Examples
1153///
1154/// ```
1155/// use http_net::{ServerConn, ServerEvent};
1156///
1157/// let mut conn = ServerConn::new();
1158/// 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");
1159/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1160/// let vias: Vec<&[u8]> = req.header_all("via").collect();
1161/// assert_eq!(vias, [&b"1.1 p1"[..], &b"1.1 p2"[..]]);
1162/// ```
1163///
1164/// The values borrow the head (`'a`), not the name (`'n`), so they outlive
1165/// a temporary name used for the lookup.
1166#[derive(Clone)]
1167pub struct HeaderValues<'a, 'n> {
1168    head: &'a [u8],
1169    fields: slice::Iter<'a, Field>,
1170    name: &'n [u8],
1171}
1172
1173impl<'a> Iterator for HeaderValues<'a, '_> {
1174    type Item = &'a [u8];
1175
1176    #[inline]
1177    fn next(&mut self) -> Option<Self::Item> {
1178        let (head, name) = (self.head, self.name);
1179        self.fields
1180            .find(|f| f.name.get(head).eq_ignore_ascii_case(name))
1181            .map(|f| f.value.get(head))
1182    }
1183
1184    #[inline]
1185    fn size_hint(&self) -> (usize, Option<usize>) {
1186        (0, self.fields.size_hint().1)
1187    }
1188}
1189
1190impl fmt::Debug for HeaderValues<'_, '_> {
1191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1192        let name = self.name;
1193        f.debug_list()
1194            .entries(self.clone().map(|value| FieldValue { name, value }))
1195            .finish()
1196    }
1197}
1198
1199/// Iterator over the elements of a list field (`#rule`) across every line
1200/// with one name: what [`RequestHead::header_list`],
1201/// [`ResponseHead::header_list`], and [`RequestHead::upgrade_protocols`]
1202/// return. Elements are trimmed of whitespace, empty ones are skipped, and
1203/// a comma inside a quoted string does not split an element.
1204///
1205/// # Examples
1206///
1207/// ```
1208/// use http_net::{ServerConn, ServerEvent};
1209///
1210/// let mut conn = ServerConn::new();
1211/// let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive, X-Trace\r\n\r\n");
1212/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1213/// let options: Vec<&[u8]> = req.header_list("connection").collect();
1214/// assert_eq!(options, [&b"keep-alive"[..], b"X-Trace"]);
1215/// ```
1216#[derive(Clone)]
1217pub struct ListElements<'a, 'n> {
1218    head: &'a [u8],
1219    fields: slice::Iter<'a, Field>,
1220    name: &'n [u8],
1221    current: ListSplit<'a>,
1222    skip_h2c: bool,
1223}
1224
1225impl<'a> Iterator for ListElements<'a, '_> {
1226    type Item = &'a [u8];
1227
1228    fn next(&mut self) -> Option<Self::Item> {
1229        loop {
1230            if let Some(e) = self.current.next() {
1231                if self.skip_h2c && is_h2c(e) {
1232                    continue;
1233                }
1234                return Some(e);
1235            }
1236            let (head, name) = (self.head, self.name);
1237            let field = self
1238                .fields
1239                .find(|f| f.name.get(head).eq_ignore_ascii_case(name))?;
1240            self.current = list_elements(field.value.get(head));
1241        }
1242    }
1243}
1244
1245impl fmt::Debug for ListElements<'_, '_> {
1246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1247        let name = self.name;
1248        f.debug_list()
1249            .entries(self.clone().map(|value| FieldValue { name, value }))
1250            .finish()
1251    }
1252}
1253
1254fn list_values<'a, 'n>(head: &'a [u8], fields: &'a [Field], name: &'n str) -> ListElements<'a, 'n> {
1255    ListElements {
1256        head,
1257        fields: fields.iter(),
1258        name: name.as_bytes(),
1259        current: list_elements(&[]),
1260        skip_h2c: false,
1261    }
1262}
1263
1264fn find_header<'a>(head: &'a [u8], fields: &[Field], name: &str) -> Option<&'a [u8]> {
1265    fields
1266        .iter()
1267        .find(|f| f.name.get(head).eq_ignore_ascii_case(name.as_bytes()))
1268        .map(|f| f.value.get(head))
1269}
1270
1271fn header_values<'a, 'n>(
1272    head: &'a [u8],
1273    fields: &'a [Field],
1274    name: &'n str,
1275) -> HeaderValues<'a, 'n> {
1276    HeaderValues {
1277        head,
1278        fields: fields.iter(),
1279        name: name.as_bytes(),
1280    }
1281}
1282
1283/// A parsed request head, borrowed from the connection's buffer.
1284///
1285/// Every accessor is a slice of the bytes that arrived; nothing is copied.
1286/// The view stays valid until the next call that mutates the connection.
1287/// Read it again later with [`ServerConn::request`](crate::ServerConn::request).
1288///
1289/// # Examples
1290///
1291/// ```
1292/// use http_net::{Method, ServerConn, ServerEvent, Version};
1293///
1294/// let mut conn = ServerConn::new();
1295/// let _ = conn.feed(b"GET /search?q=rust HTTP/1.1\r\nHost: example.com\r\n\r\n");
1296/// let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1297/// assert_eq!(req.method(), Method::Get);
1298/// assert_eq!(req.path(), "/search");
1299/// assert_eq!(req.query(), Some("q=rust"));
1300/// assert_eq!(req.version(), Version::Http11);
1301/// assert_eq!(req.host(), Some("example.com"));
1302/// assert!(req.keep_alive());
1303/// ```
1304#[derive(Clone, Copy)]
1305pub struct RequestHead<'a> {
1306    head: &'a [u8],
1307    fields: &'a [Field],
1308    info: &'a RequestInfo,
1309}
1310
1311impl<'a> RequestHead<'a> {
1312    pub(crate) const fn new(head: &'a [u8], fields: &'a [Field], info: &'a RequestInfo) -> Self {
1313        Self { head, fields, info }
1314    }
1315
1316    /// The bytes the spans index (the head, possibly followed by more
1317    /// input), the field records, and the interpreted facts.
1318    pub(crate) const fn parts(&self) -> (&'a [u8], &'a [Field], &'a RequestInfo) {
1319        (self.head, self.fields, self.info)
1320    }
1321
1322    /// The method, classified.
1323    ///
1324    /// # Examples
1325    ///
1326    /// ```
1327    /// # use http_net::{Method, ServerConn, ServerEvent};
1328    /// # let mut conn = ServerConn::new();
1329    /// # let _ = conn.feed(b"DELETE /x HTTP/1.1\r\nHost: a\r\n\r\n");
1330    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1331    /// assert_eq!(req.method(), Method::Delete);
1332    /// ```
1333    #[must_use]
1334    pub fn method(&self) -> Method {
1335        self.info.method
1336    }
1337
1338    /// The method exactly as received.
1339    ///
1340    /// # Examples
1341    ///
1342    /// ```
1343    /// # use http_net::{Method, ServerConn, ServerEvent};
1344    /// # let mut conn = ServerConn::new();
1345    /// # let _ = conn.feed(b"PROPFIND /x HTTP/1.1\r\nHost: a\r\n\r\n");
1346    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1347    /// assert_eq!(req.method(), Method::Other);
1348    /// assert_eq!(req.method_str(), "PROPFIND");
1349    /// ```
1350    #[must_use]
1351    pub fn method_str(&self) -> &'a str {
1352        core::str::from_utf8(self.info.method_span.get(self.head)).unwrap_or("")
1353    }
1354
1355    /// The request target exactly as received (origin form `/path?query`,
1356    /// absolute form, authority form for `CONNECT`, or `*`).
1357    ///
1358    /// # Examples
1359    ///
1360    /// ```
1361    /// # use http_net::{ServerConn, ServerEvent};
1362    /// # let mut conn = ServerConn::new();
1363    /// # let _ = conn.feed(b"GET /a%20b?x=1 HTTP/1.1\r\nHost: a\r\n\r\n");
1364    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1365    /// assert_eq!(req.target(), "/a%20b?x=1");
1366    /// ```
1367    #[must_use]
1368    pub fn target(&self) -> &'a str {
1369        core::str::from_utf8(self.info.target.get(self.head)).unwrap_or("")
1370    }
1371
1372    /// Which of the four RFC 9112 section 3.2 forms the target uses.
1373    ///
1374    /// # Examples
1375    ///
1376    /// ```
1377    /// # use http_net::{ServerConn, ServerEvent, TargetForm};
1378    /// # let mut conn = ServerConn::new();
1379    /// # let _ = conn.feed(b"GET http://a.test/x HTTP/1.1\r\nHost: a.test\r\n\r\n");
1380    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1381    /// assert_eq!(req.target_form(), TargetForm::Absolute);
1382    /// ```
1383    #[must_use]
1384    pub fn target_form(&self) -> TargetForm {
1385        self.info.target_form
1386    }
1387
1388    /// The path: the target up to (not including) the first `?`, with
1389    /// percent-encoding left as received.
1390    ///
1391    /// For an absolute-form target (`http://host/p?q`) this is the path
1392    /// after the authority (`/p`), and `/` when that path is empty, so a
1393    /// router sees the same path whichever form the client used. For `*`
1394    /// and for `CONNECT`'s authority form it is the whole target.
1395    ///
1396    /// # Examples
1397    ///
1398    /// ```
1399    /// # use http_net::{ServerConn, ServerEvent};
1400    /// # let mut conn = ServerConn::new();
1401    /// # let _ = conn.feed(b"GET /files/a.txt?v=2 HTTP/1.1\r\nHost: a\r\n\r\n");
1402    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1403    /// assert_eq!(req.path(), "/files/a.txt");
1404    ///
1405    /// # let mut conn = ServerConn::new();
1406    /// # let _ = conn.feed(b"GET http://a/files/b.txt HTTP/1.1\r\nHost: a\r\n\r\n");
1407    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1408    /// assert_eq!(req.path(), "/files/b.txt");
1409    /// ```
1410    #[must_use]
1411    pub fn path(&self) -> &'a str {
1412        let origin = self.origin();
1413        let path = origin.split_once('?').map_or(origin, |(p, _)| p);
1414        if path.is_empty() && self.info.authority.is_some() {
1415            // RFC 9110 section 4.2.3: an empty path in an http URI is "/".
1416            "/"
1417        } else {
1418            path
1419        }
1420    }
1421
1422    /// The query after the first `?`, if there is one.
1423    ///
1424    /// # Examples
1425    ///
1426    /// ```
1427    /// # use http_net::{ServerConn, ServerEvent};
1428    /// # let mut conn = ServerConn::new();
1429    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\n\r\n");
1430    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1431    /// assert_eq!(req.query(), None);
1432    /// ```
1433    #[must_use]
1434    pub fn query(&self) -> Option<&'a str> {
1435        self.origin().split_once('?').map(|(_, q)| q)
1436    }
1437
1438    /// The path-and-query part of the target.
1439    fn origin(&self) -> &'a str {
1440        core::str::from_utf8(self.info.origin.get(self.head)).unwrap_or("")
1441    }
1442
1443    /// The protocol version.
1444    ///
1445    /// # Examples
1446    ///
1447    /// ```
1448    /// # use http_net::{ServerConn, ServerEvent, Version};
1449    /// # let mut conn = ServerConn::new();
1450    /// # let _ = conn.feed(b"GET /x HTTP/1.0\r\n\r\n");
1451    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1452    /// assert_eq!(req.version(), Version::Http10);
1453    /// ```
1454    #[must_use]
1455    pub fn version(&self) -> Version {
1456        self.info.version
1457    }
1458
1459    /// All fields in arrival order.
1460    ///
1461    /// # Examples
1462    ///
1463    /// ```
1464    /// # use http_net::{ServerConn, ServerEvent};
1465    /// # let mut conn = ServerConn::new();
1466    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nAccept: */*\r\n\r\n");
1467    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1468    /// assert_eq!(req.headers().len(), 2);
1469    /// ```
1470    #[must_use]
1471    pub fn headers(&self) -> Headers<'a> {
1472        Headers {
1473            head: self.head,
1474            fields: self.fields.iter(),
1475        }
1476    }
1477
1478    /// The value of the first field named `name` (ASCII case-insensitive).
1479    ///
1480    /// # Examples
1481    ///
1482    /// ```
1483    /// # use http_net::{ServerConn, ServerEvent};
1484    /// # let mut conn = ServerConn::new();
1485    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nAccept:  text/html \r\n\r\n");
1486    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1487    /// assert_eq!(req.header("accept"), Some(&b"text/html"[..]));
1488    /// assert_eq!(req.header("cookie"), None);
1489    /// ```
1490    #[must_use]
1491    pub fn header(&self, name: &str) -> Option<&'a [u8]> {
1492        find_header(self.head, self.fields, name)
1493    }
1494
1495    /// Like [`header`](Self::header), but only when the value is UTF-8.
1496    ///
1497    /// # Examples
1498    ///
1499    /// ```
1500    /// # use http_net::{ServerConn, ServerEvent};
1501    /// # let mut conn = ServerConn::new();
1502    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nX: \xff\r\n\r\n");
1503    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1504    /// assert_eq!(req.header_str("host"), Some("a"));
1505    /// assert_eq!(req.header_str("x"), None);
1506    /// ```
1507    #[must_use]
1508    pub fn header_str(&self, name: &str) -> Option<&'a str> {
1509        self.header(name).and_then(|v| core::str::from_utf8(v).ok())
1510    }
1511
1512    /// The values of every field named `name` (ASCII case-insensitive), in
1513    /// arrival order: for fields that may be repeated, such as `via`,
1514    /// `forwarded`, or `cookie` from clients that send one line per cookie.
1515    ///
1516    /// # Examples
1517    ///
1518    /// ```
1519    /// # use http_net::{ServerConn, ServerEvent};
1520    /// # let mut conn = ServerConn::new();
1521    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nCookie: a=1\r\nCookie: b=2\r\n\r\n");
1522    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1523    /// let cookies: Vec<&[u8]> = req.header_all("cookie").collect();
1524    /// assert_eq!(cookies, [&b"a=1"[..], &b"b=2"[..]]);
1525    /// assert_eq!(req.header_all("accept").count(), 0);
1526    ///
1527    /// // The values borrow the head, not the name.
1528    /// let first = {
1529    ///     let name = String::from("COOKIE");
1530    ///     req.header_all(&name).next()
1531    /// };
1532    /// assert_eq!(first, Some(&b"a=1"[..]));
1533    /// ```
1534    #[must_use]
1535    pub fn header_all<'n>(&self, name: &'n str) -> HeaderValues<'a, 'n> {
1536        header_values(self.head, self.fields, name)
1537    }
1538
1539    /// The declared `Content-Length`, if the request has one. Unlike
1540    /// [`framing`](Self::framing), which reports `Content-Length: 0` as
1541    /// [`BodyFraming::None`], this tells `Some(0)` from an absent field.
1542    ///
1543    /// # Examples
1544    ///
1545    /// ```
1546    /// # use http_net::{BodyFraming, ServerConn, ServerEvent};
1547    /// # let mut conn = ServerConn::new();
1548    /// # let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nContent-Length: 0\r\n\r\n");
1549    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1550    /// assert_eq!(req.framing(), BodyFraming::None);
1551    /// assert_eq!(req.content_length(), Some(0));
1552    /// ```
1553    #[must_use]
1554    pub fn content_length(&self) -> Option<u64> {
1555        self.info.content_length
1556    }
1557
1558    /// The authority the request is for (`host [":" port]`), if known.
1559    ///
1560    /// This is the `Host` field, except for an absolute-form target
1561    /// (`GET http://example.com/ HTTP/1.1`), whose authority wins: RFC 9112
1562    /// section 3.2.2 requires a server to ignore `Host` then, so the two can
1563    /// never be read differently. The raw field stays available through
1564    /// `header("host")`. HTTP/1.1 requests always carry a valid `Host`;
1565    /// HTTP/1.0 requests may not, and an empty `Host` (a target with no
1566    /// authority) is reported as `Some("")`.
1567    ///
1568    /// # Examples
1569    ///
1570    /// ```
1571    /// # use http_net::{ServerConn, ServerEvent};
1572    /// # let mut conn = ServerConn::new();
1573    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: 127.0.0.1:8080\r\n\r\n");
1574    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1575    /// assert_eq!(req.host(), Some("127.0.0.1:8080"));
1576    ///
1577    /// # let mut conn = ServerConn::new();
1578    /// # let _ = conn.feed(b"GET http://a.test/x HTTP/1.1\r\nHost: b.test\r\n\r\n");
1579    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1580    /// assert_eq!(req.host(), Some("a.test"));
1581    /// assert_eq!(req.header("host"), Some(&b"b.test"[..]));
1582    /// ```
1583    #[must_use]
1584    pub fn host(&self) -> Option<&'a str> {
1585        self.info
1586            .authority
1587            .or(self.info.host)
1588            .and_then(|s| core::str::from_utf8(s.get(self.head)).ok())
1589    }
1590
1591    /// Whether the client sent `Expect: 100-continue` and is waiting for a
1592    /// `100 Continue` before sending the body. Only HTTP/1.1 requests that
1593    /// have a body report it (RFC 9110 section 10.1.1).
1594    ///
1595    /// Answer it before reading the body: either
1596    /// [`ServerConn::send_continue`](crate::ServerConn::send_continue), or a
1597    /// final response straight away (which closes the connection afterwards,
1598    /// since the body was not read). The blocking `Server` sends
1599    /// `100 Continue` itself.
1600    ///
1601    /// # Examples
1602    ///
1603    /// ```
1604    /// # use http_net::{ServerConn, ServerEvent};
1605    /// # let mut conn = ServerConn::new();
1606    /// # let _ = conn.feed(b"PUT /f HTTP/1.1\r\nHost: a\r\nExpect: 100-continue\r\nContent-Length: 9\r\n\r\n");
1607    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1608    /// assert!(req.expects_continue());
1609    /// ```
1610    #[must_use]
1611    pub fn expects_continue(&self) -> bool {
1612        self.info.expect_continue
1613    }
1614
1615    /// How the request body is delimited.
1616    ///
1617    /// # Examples
1618    ///
1619    /// ```
1620    /// # use http_net::{BodyFraming, ServerConn, ServerEvent};
1621    /// # let mut conn = ServerConn::new();
1622    /// # let _ = conn.feed(b"POST /x HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n");
1623    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1624    /// assert_eq!(req.framing(), BodyFraming::Chunked);
1625    /// ```
1626    #[must_use]
1627    pub fn framing(&self) -> BodyFraming {
1628        self.info.framing
1629    }
1630
1631    /// Whether the client allows the connection to stay open after this
1632    /// exchange (HTTP/1.1 unless `Connection: close`; HTTP/1.0 only with
1633    /// `Connection: keep-alive`).
1634    ///
1635    /// # Examples
1636    ///
1637    /// ```
1638    /// # use http_net::{ServerConn, ServerEvent};
1639    /// # let mut conn = ServerConn::new();
1640    /// # let _ = conn.feed(b"GET /x HTTP/1.1\r\nHost: a\r\nConnection: close\r\n\r\n");
1641    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1642    /// assert!(!req.keep_alive());
1643    /// ```
1644    #[must_use]
1645    pub fn keep_alive(&self) -> bool {
1646        self.info.keep_alive
1647    }
1648
1649    /// Whether this is an HTTP/1.1 request to switch protocols: `Connection`
1650    /// lists `upgrade` and an `Upgrade` field offers at least one protocol
1651    /// other than `h2c` (read the offer with `header("upgrade")`). Answer
1652    /// with [`Response::switching_protocols`](crate::Response::switching_protocols)
1653    /// naming an offered protocol to hand the connection over.
1654    ///
1655    /// `h2c` is never an offer: RFC 9113 section 3.1 deprecates the
1656    /// HTTP/2 upgrade, and a proxy that forwards it blindly is open to h2c
1657    /// smuggling. A request offering only `h2c` is served as HTTP/1.1.
1658    ///
1659    /// # Examples
1660    ///
1661    /// ```
1662    /// # use http_net::{ServerConn, ServerEvent};
1663    /// # let mut conn = ServerConn::new();
1664    /// # let _ = conn.feed(b"GET /ws HTTP/1.1\r\nHost: a\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n");
1665    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1666    /// assert!(req.is_upgrade());
1667    /// assert_eq!(req.header("upgrade"), Some(&b"websocket"[..]));
1668    ///
1669    /// # let mut conn = ServerConn::new();
1670    /// # 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");
1671    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1672    /// assert!(!req.is_upgrade());
1673    /// ```
1674    #[must_use]
1675    pub fn is_upgrade(&self) -> bool {
1676        self.info.upgrade
1677    }
1678
1679    /// Whether the request carries an expectation other than
1680    /// `100-continue` (any `Expect` list element, any HTTP version), which
1681    /// a server may answer with `417 Expectation Failed` (RFC 9110 section
1682    /// 10.1.1). The core never answers it by itself; the blocking server
1683    /// does. The expectation never changes how the body is framed.
1684    ///
1685    /// # Examples
1686    ///
1687    /// ```
1688    /// # use http_net::{ServerConn, ServerEvent};
1689    /// # let mut conn = ServerConn::new();
1690    /// # 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");
1691    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1692    /// assert!(req.expects_continue());
1693    /// assert!(req.has_unknown_expectation());
1694    /// ```
1695    #[must_use]
1696    pub fn has_unknown_expectation(&self) -> bool {
1697        self.info.unknown_expectation
1698    }
1699
1700    /// The protocols the request's `Upgrade` field offers, in order, as
1701    /// product tokens (`websocket`, `foo/2`), across every `Upgrade` line;
1702    /// `h2c` is left out (it is never an offer). Empty unless
1703    /// [`is_upgrade`](Self::is_upgrade).
1704    ///
1705    /// # Examples
1706    ///
1707    /// ```
1708    /// # use http_net::{ServerConn, ServerEvent};
1709    /// # let mut conn = ServerConn::new();
1710    /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: upgrade\r\nUpgrade: h2c, websocket/13, irc\r\n\r\n");
1711    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1712    /// let offered: Vec<&[u8]> = req.upgrade_protocols().collect();
1713    /// assert_eq!(offered, [&b"websocket/13"[..], b"irc"]);
1714    /// ```
1715    #[must_use]
1716    pub fn upgrade_protocols(&self) -> ListElements<'a, 'static> {
1717        let mut list = list_values(self.head, self.fields, "upgrade");
1718        list.skip_h2c = true;
1719        if !self.info.upgrade {
1720            list.fields = [].iter();
1721        }
1722        list
1723    }
1724
1725    /// The options the request's `Connection` field lists, across every
1726    /// `Connection` line, in order (`close`, `keep-alive`, `upgrade`, and the
1727    /// names of fields that are hop-by-hop for this message). Compare them
1728    /// ASCII case-insensitively. A proxy passes them to
1729    /// [`is_hop_by_hop`](crate::is_hop_by_hop).
1730    ///
1731    /// # Examples
1732    ///
1733    /// ```
1734    /// # use http_net::{ServerConn, ServerEvent};
1735    /// # let mut conn = ServerConn::new();
1736    /// # let _ = conn.feed(b"GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive, X-Trace\r\n\r\n");
1737    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1738    /// let options: Vec<&[u8]> = req.connection_options().collect();
1739    /// assert_eq!(options, [&b"keep-alive"[..], b"X-Trace"]);
1740    /// ```
1741    #[must_use]
1742    pub fn connection_options(&self) -> ListElements<'a, 'static> {
1743        list_values(self.head, self.fields, "connection")
1744    }
1745
1746    /// The elements of a comma-separated list field (`#rule`, RFC 9110
1747    /// section 5.6.1) across every line with this name, in order, trimmed
1748    /// of whitespace, empty elements skipped. A comma inside a quoted
1749    /// string does not split an element.
1750    ///
1751    /// # Examples
1752    ///
1753    /// ```
1754    /// # use http_net::{ServerConn, ServerEvent};
1755    /// # let mut conn = ServerConn::new();
1756    /// # 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");
1757    /// # let ServerEvent::Request(req) = conn.poll().unwrap() else { panic!() };
1758    /// let accept: Vec<&[u8]> = req.header_list("accept").collect();
1759    /// assert_eq!(accept, [&b"text/html"[..], b"x/y;q=\"0.5,1\""]);
1760    /// ```
1761    #[must_use]
1762    pub fn header_list<'n>(&self, name: &'n str) -> ListElements<'a, 'n> {
1763        list_values(self.head, self.fields, name)
1764    }
1765
1766    /// Whether the request's `Upgrade` field offers `protocol` (see
1767    /// [`Response::switching_protocols`](crate::Response::switching_protocols)).
1768    pub(crate) fn offers(&self, protocol: &[u8]) -> bool {
1769        self.info.upgrade
1770            && self
1771                .header_all("upgrade")
1772                .any(|v| list_elements(v).any(|e| protocol_matches(protocol, e)))
1773    }
1774}
1775
1776/// Shows method, target, version, fields, and framing; the values of
1777/// credential fields are replaced by `<redacted N bytes>`.
1778impl fmt::Debug for RequestHead<'_> {
1779    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1780        f.debug_struct("RequestHead")
1781            .field("method", &self.method_str())
1782            .field("target", &self.target())
1783            .field("version", &self.version())
1784            .field("headers", &self.headers())
1785            .field("framing", &self.framing())
1786            .finish()
1787    }
1788}
1789
1790/// A parsed response head, borrowed from the client connection's buffer.
1791///
1792/// # Examples
1793///
1794/// ```
1795/// use http_net::{ClientConn, ClientEvent, Request};
1796///
1797/// let mut conn = ClientConn::new();
1798/// let mut out = Vec::new();
1799/// conn.send_request(&Request::get("/").header("host", "a"), &mut out).unwrap();
1800/// let _ = conn.feed(b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n");
1801/// let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1802/// assert_eq!(resp.status(), 404);
1803/// assert_eq!(resp.reason(), "Not Found");
1804/// ```
1805#[derive(Clone, Copy)]
1806pub struct ResponseHead<'a> {
1807    head: &'a [u8],
1808    fields: &'a [Field],
1809    info: &'a ResponseInfo,
1810}
1811
1812impl<'a> ResponseHead<'a> {
1813    pub(crate) const fn new(head: &'a [u8], fields: &'a [Field], info: &'a ResponseInfo) -> Self {
1814        Self { head, fields, info }
1815    }
1816
1817    /// As [`RequestHead::parts`], for a response.
1818    pub(crate) const fn parts(&self) -> (&'a [u8], &'a [Field], &'a ResponseInfo) {
1819        (self.head, self.fields, self.info)
1820    }
1821
1822    /// The status code (`100..=599`).
1823    ///
1824    /// # Examples
1825    ///
1826    /// ```
1827    /// # use http_net::{ClientConn, ClientEvent, Request};
1828    /// # let mut conn = ClientConn::new();
1829    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1830    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1831    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1832    /// assert_eq!(resp.status(), 200);
1833    /// ```
1834    #[must_use]
1835    pub fn status(&self) -> u16 {
1836        self.info.status
1837    }
1838
1839    /// The reason phrase, if it is UTF-8 (it carries no meaning; RFC 9112
1840    /// tells clients to ignore it). Empty for a status line without one,
1841    /// including `HTTP/1.1 200` with no space after the code.
1842    ///
1843    /// # Examples
1844    ///
1845    /// ```
1846    /// # use http_net::{ClientConn, ClientEvent, Request};
1847    /// # let mut conn = ClientConn::new();
1848    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1849    /// # let _ = conn.feed(b"HTTP/1.1 200 \r\nContent-Length: 0\r\n\r\n");
1850    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1851    /// assert_eq!(resp.reason(), "");
1852    /// ```
1853    #[must_use]
1854    pub fn reason(&self) -> &'a str {
1855        core::str::from_utf8(self.info.reason.get(self.head)).unwrap_or("")
1856    }
1857
1858    /// The protocol version.
1859    ///
1860    /// # Examples
1861    ///
1862    /// ```
1863    /// # use http_net::{ClientConn, ClientEvent, Request, Version};
1864    /// # let mut conn = ClientConn::new();
1865    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1866    /// # let _ = conn.feed(b"HTTP/1.0 200 OK\r\n\r\n");
1867    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1868    /// assert_eq!(resp.version(), Version::Http10);
1869    /// ```
1870    #[must_use]
1871    pub fn version(&self) -> Version {
1872        self.info.version
1873    }
1874
1875    /// All fields in arrival order.
1876    ///
1877    /// # Examples
1878    ///
1879    /// ```
1880    /// # use http_net::{ClientConn, ClientEvent, Request};
1881    /// # let mut conn = ClientConn::new();
1882    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1883    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\nX: y\r\n\r\n");
1884    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1885    /// assert_eq!(resp.headers().count(), 2);
1886    /// ```
1887    #[must_use]
1888    pub fn headers(&self) -> Headers<'a> {
1889        Headers {
1890            head: self.head,
1891            fields: self.fields.iter(),
1892        }
1893    }
1894
1895    /// The value of the first field named `name` (ASCII case-insensitive).
1896    ///
1897    /// # Examples
1898    ///
1899    /// ```
1900    /// # use http_net::{ClientConn, ClientEvent, Request};
1901    /// # let mut conn = ClientConn::new();
1902    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1903    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n");
1904    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1905    /// assert_eq!(resp.header("content-type"), Some(&b"text/plain"[..]));
1906    /// ```
1907    #[must_use]
1908    pub fn header(&self, name: &str) -> Option<&'a [u8]> {
1909        find_header(self.head, self.fields, name)
1910    }
1911
1912    /// Like [`header`](Self::header), but only when the value is UTF-8.
1913    ///
1914    /// # Examples
1915    ///
1916    /// ```
1917    /// # use http_net::{ClientConn, ClientEvent, Request};
1918    /// # let mut conn = ClientConn::new();
1919    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1920    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nServer: x\r\nContent-Length: 0\r\n\r\n");
1921    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1922    /// assert_eq!(resp.header_str("server"), Some("x"));
1923    /// ```
1924    #[must_use]
1925    pub fn header_str(&self, name: &str) -> Option<&'a str> {
1926        self.header(name).and_then(|v| core::str::from_utf8(v).ok())
1927    }
1928
1929    /// The values of every field named `name`, in arrival order. Each
1930    /// `Set-Cookie` is its own field (they are never comma-joined), so
1931    /// this is how a client reads all of them.
1932    ///
1933    /// # Examples
1934    ///
1935    /// ```
1936    /// # use http_net::{ClientConn, ClientEvent, Request};
1937    /// # let mut conn = ClientConn::new();
1938    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1939    /// # 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");
1940    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1941    /// let cookies: Vec<&[u8]> = resp.header_all("set-cookie").collect();
1942    /// assert_eq!(cookies, [&b"a=1"[..], &b"b=2; Path=/"[..]]);
1943    /// ```
1944    #[must_use]
1945    pub fn header_all<'n>(&self, name: &'n str) -> HeaderValues<'a, 'n> {
1946        header_values(self.head, self.fields, name)
1947    }
1948
1949    /// The declared `Content-Length`, if the response has one, whatever the
1950    /// framing rules made of it (a `HEAD` response's length is reported
1951    /// here while [`framing`](Self::framing) is `None`).
1952    ///
1953    /// # Examples
1954    ///
1955    /// ```
1956    /// # use http_net::{BodyFraming, ClientConn, ClientEvent, Request};
1957    /// # let mut conn = ClientConn::new();
1958    /// # conn.send_request(&Request::head("/").header("host", "a"), &mut Vec::new()).unwrap();
1959    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 1234\r\n\r\n");
1960    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1961    /// assert_eq!(resp.framing(), BodyFraming::None);
1962    /// assert_eq!(resp.content_length(), Some(1234));
1963    /// ```
1964    #[must_use]
1965    pub fn content_length(&self) -> Option<u64> {
1966        self.info.content_length
1967    }
1968
1969    /// The elements of a list field across every line with this name (see
1970    /// [`RequestHead::header_list`]).
1971    ///
1972    /// # Examples
1973    ///
1974    /// ```
1975    /// # use http_net::{ClientConn, ClientEvent, Request};
1976    /// # let mut conn = ClientConn::new();
1977    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1978    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nVary: accept\r\nVary: origin, cookie\r\nContent-Length: 0\r\n\r\n");
1979    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1980    /// assert_eq!(resp.header_list("vary").count(), 3);
1981    /// ```
1982    #[must_use]
1983    pub fn header_list<'n>(&self, name: &'n str) -> ListElements<'a, 'n> {
1984        list_values(self.head, self.fields, name)
1985    }
1986
1987    /// Whether this is an interim (1xx) response head, as reported by
1988    /// [`ClientEvent::Informational`](crate::ClientEvent::Informational).
1989    ///
1990    /// # Examples
1991    ///
1992    /// ```
1993    /// # use http_net::{ClientConn, ClientEvent, Request};
1994    /// # let mut conn = ClientConn::new();
1995    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
1996    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
1997    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
1998    /// assert!(!resp.is_informational());
1999    /// ```
2000    #[must_use]
2001    pub fn is_informational(&self) -> bool {
2002        (100..200).contains(&self.info.status)
2003    }
2004
2005    /// How the response body is delimited (accounts for `HEAD` requests and
2006    /// bodiless status codes).
2007    ///
2008    /// # Examples
2009    ///
2010    /// ```
2011    /// # use http_net::{BodyFraming, ClientConn, ClientEvent, Request};
2012    /// # let mut conn = ClientConn::new();
2013    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
2014    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\n\r\n");
2015    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
2016    /// assert_eq!(resp.framing(), BodyFraming::UntilClose);
2017    /// ```
2018    #[must_use]
2019    pub fn framing(&self) -> BodyFraming {
2020        self.info.framing
2021    }
2022
2023    /// Whether the connection can carry another request after this response.
2024    ///
2025    /// # Examples
2026    ///
2027    /// ```
2028    /// # use http_net::{ClientConn, ClientEvent, Request};
2029    /// # let mut conn = ClientConn::new();
2030    /// # conn.send_request(&Request::get("/").header("host", "a"), &mut Vec::new()).unwrap();
2031    /// # let _ = conn.feed(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
2032    /// # let ClientEvent::Response(resp) = conn.poll().unwrap() else { panic!() };
2033    /// assert!(resp.keep_alive());
2034    /// ```
2035    #[must_use]
2036    pub fn keep_alive(&self) -> bool {
2037        self.info.keep_alive
2038    }
2039}
2040
2041/// Shows status, reason, version, fields, and framing; the values of
2042/// credential fields (`set-cookie` above all) are replaced by
2043/// `<redacted N bytes>`.
2044impl fmt::Debug for ResponseHead<'_> {
2045    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2046        f.debug_struct("ResponseHead")
2047            .field("status", &self.status())
2048            .field("reason", &self.reason())
2049            .field("version", &self.version())
2050            .field("headers", &self.headers())
2051            .field("framing", &self.framing())
2052            .finish()
2053    }
2054}
2055
2056#[cfg(test)]
2057mod tests {
2058    use alloc::vec::Vec;
2059
2060    use super::*;
2061
2062    /// Lines built from the bytes that decide field parsing, at random.
2063    fn random_lines(count: usize) -> Vec<Vec<u8>> {
2064        const BYTES: &[u8] = b"aZ09-!~:: \t\r\n\x00\x7f\x80\xff\"(,";
2065        let mut state = 0x2545_f491_4f6c_dd1du64;
2066        let mut next = move || {
2067            state ^= state << 13;
2068            state ^= state >> 7;
2069            state ^= state << 17;
2070            state
2071        };
2072        // Mostly the shape a field line has (a name, a colon, a value), with
2073        // the deciding bytes mixed in now and then, so lines land on both
2074        // sides of what the fast path accepts.
2075        let mut pick = move |plain: &[u8]| {
2076            if next() % 12 == 0 {
2077                BYTES[(next() % BYTES.len() as u64) as usize]
2078            } else {
2079                plain[(next() % plain.len() as u64) as usize]
2080            }
2081        };
2082        (0..count)
2083            .map(|i| {
2084                let mut line = Vec::new();
2085                for _ in 0..(i % 9) {
2086                    line.push(pick(b"abcXYZ019-_.!~"));
2087                }
2088                line.push(pick(b":"));
2089                for _ in 0..(i % 23) {
2090                    line.push(pick(b"  abc XYZ 019 ,;=/\"()[]{}"));
2091                }
2092                if i % 5 != 0 {
2093                    line.extend_from_slice(b"\r\n");
2094                }
2095                line
2096            })
2097            .collect()
2098    }
2099
2100    #[test]
2101    fn test_fast_field_agrees_with_the_general_path() {
2102        let mut fast = 0;
2103        for line in random_lines(300_000).into_iter().chain([
2104            b"Host: a\r\n".to_vec(),
2105            b"X:\r\n".to_vec(),
2106            b"X:   \r\n".to_vec(),
2107            b"X:  a  b  \r\n".to_vec(),
2108            b"X: a\tb\r\n".to_vec(),
2109            b"X: a\r".to_vec(),
2110            b"X: a\n".to_vec(),
2111            b" X: a\r\n".to_vec(),
2112            b"X : a\r\n".to_vec(),
2113            b"X: \x80\r\n".to_vec(),
2114            b"X: a\rb\r\n".to_vec(),
2115        ]) {
2116            let Some((field, next)) = fast_field(&line, 0) else {
2117                continue;
2118            };
2119            fast += 1;
2120            // The general path on the same line: the LF it finds, then the
2121            // field it parses.
2122            let lf = find_byte(b'\n', &line).expect("an accepted line has an LF");
2123            assert_eq!(next, lf + 1, "{line:?}");
2124            assert_eq!(line[lf - 1], b'\r', "{line:?}");
2125            assert_eq!(parse_field(&line[..lf - 1], 0), Ok(field), "{line:?}");
2126        }
2127        assert!(fast > 1_000, "the fast path accepted only {fast} lines");
2128    }
2129
2130    #[test]
2131    fn test_scan_with_and_without_the_fast_path_agree_at_every_split() {
2132        // Whole input takes the fast path; one byte at a time cannot (a
2133        // line is never complete when its search starts), so it exercises
2134        // the general path. Both must report the same fields and errors.
2135        let heads: [&[u8]; 6] = [
2136            b"GET / HTTP/1.1\r\nHost: a\r\nX:  b  \r\nY:\r\n\r\n",
2137            b"GET / HTTP/1.1\r\nHost: a\r\nX: a\tb\r\n\r\n",
2138            b"GET / HTTP/1.1\r\nHost: a\r\nX: a\rb\r\n\r\n",
2139            b"GET / HTTP/1.1\r\nHost: a\r\nX : b\r\n\r\n",
2140            b"GET / HTTP/1.1\r\nHost: a\r\n X: b\r\n\r\n",
2141            b"GET / HTTP/1.1\r\nHost: a\r\nX: \x80\x81\r\n\r\n",
2142        ];
2143        let fields = |s: &HeadScanner| {
2144            s.fields
2145                .iter()
2146                .map(|f| (f.name, f.value))
2147                .collect::<Vec<_>>()
2148        };
2149        for head in heads {
2150            let mut whole = HeadScanner::new();
2151            let whole_result = whole.advance(head, &Limits::new(), HeadKind::Request, true);
2152            let mut split = HeadScanner::new();
2153            let mut split_result = Ok(Scan::Partial);
2154            for end in 1..=head.len() {
2155                split_result = split.advance(&head[..end], &Limits::new(), HeadKind::Request, true);
2156                if !matches!(split_result, Ok(Scan::Partial)) {
2157                    break;
2158                }
2159            }
2160            assert_eq!(whole_result, split_result, "{head:?}");
2161            assert_eq!(fields(&whole), fields(&split), "{head:?}");
2162        }
2163    }
2164
2165    fn scan(msg: &[u8], kind: HeadKind) -> Result<(HeadScanner, usize), HttpError> {
2166        let mut s = HeadScanner::new();
2167        match s.advance(msg, &Limits::new(), kind, true)? {
2168            Scan::Done(n) => Ok((s, n)),
2169            Scan::Partial => Err(HttpError::UnexpectedEof),
2170        }
2171    }
2172
2173    #[test]
2174    fn test_scanner_resumes_without_rescanning() {
2175        let msg = b"GET / HTTP/1.1\r\nHost: a\r\n\r\n";
2176        let mut s = HeadScanner::new();
2177        for end in 1..msg.len() {
2178            assert!(matches!(
2179                s.advance(&msg[..end], &Limits::new(), HeadKind::Request, true),
2180                Ok(Scan::Partial)
2181            ));
2182        }
2183        assert!(matches!(
2184            s.advance(msg, &Limits::new(), HeadKind::Request, true),
2185            Ok(Scan::Done(n)) if n == msg.len()
2186        ));
2187        assert_eq!(s.fields.len(), 1);
2188    }
2189
2190    #[test]
2191    fn test_scanner_rejects_line_shapes() {
2192        let cases: &[(&[u8], HttpError)] = &[
2193            (b"GET / HTTP/1.1\nHost: a\r\n\r\n", HttpError::BareLf),
2194            (b"GET / HTTP/1.1\r\n Host: a\r\n\r\n", HttpError::ObsFold),
2195            (
2196                b"GET / HTTP/1.1\r\nHost : a\r\n\r\n",
2197                HttpError::WhitespaceBeforeColon,
2198            ),
2199            (
2200                b"GET / HTTP/1.1\r\nHost\r\n\r\n",
2201                HttpError::InvalidHeaderName,
2202            ),
2203            (
2204                b"GET / HTTP/1.1\r\n: a\r\n\r\n",
2205                HttpError::InvalidHeaderName,
2206            ),
2207            (b"GET / HTTP/1.1\r\nHo\rst: a\r\n\r\n", HttpError::BareCr),
2208            (b"GET / HTTP/1.1\r\nHost: a\rb\r\n\r\n", HttpError::BareCr),
2209            (b"GET /\r HTTP/1.1\r\n\r\n", HttpError::BareCr),
2210            (
2211                b"GET / HTTP/1.1\r\nHost: a\x00\r\n\r\n",
2212                HttpError::InvalidHeaderValue,
2213            ),
2214        ];
2215        for (msg, err) in cases {
2216            assert_eq!(scan(msg, HeadKind::Request).err(), Some(*err), "{msg:?}");
2217        }
2218    }
2219
2220    #[test]
2221    fn test_scanner_skips_leading_empty_lines_for_requests_only() {
2222        assert!(scan(b"\r\n\r\nGET / HTTP/1.1\r\n\r\n", HeadKind::Request).is_ok());
2223        assert_eq!(
2224            scan(b"\r\nHTTP/1.1 200 OK\r\n\r\n", HeadKind::Response).err(),
2225            Some(HttpError::InvalidStartLine)
2226        );
2227    }
2228
2229    #[test]
2230    fn test_scanner_enforces_limits_at_boundaries() {
2231        let limits = Limits::new().with_max_start_line(16);
2232        // "GET / HTTP/1.1\r\n" is exactly 16 bytes.
2233        let mut s = HeadScanner::new();
2234        assert!(
2235            s.advance(b"GET / HTTP/1.1\r\n\r\n", &limits, HeadKind::Request, true)
2236                .is_ok()
2237        );
2238        let mut s = HeadScanner::new();
2239        assert_eq!(
2240            s.advance(b"GET /a HTTP/1.1\r\n\r\n", &limits, HeadKind::Request, true)
2241                .err(),
2242            Some(HttpError::StartLineTooLong)
2243        );
2244        // Partial input already at the budget fails without waiting for LF.
2245        let mut s = HeadScanner::new();
2246        assert_eq!(
2247            s.advance(b"GET /aaaaaaaaaaaa", &limits, HeadKind::Request, true)
2248                .err(),
2249            Some(HttpError::StartLineTooLong)
2250        );
2251
2252        let limits = Limits::new().with_max_headers(1);
2253        let mut s = HeadScanner::new();
2254        assert_eq!(
2255            s.advance(
2256                b"GET / HTTP/1.1\r\nA: 1\r\nB: 2\r\n\r\n",
2257                &limits,
2258                HeadKind::Request,
2259                true
2260            )
2261            .err(),
2262            Some(HttpError::TooManyHeaders)
2263        );
2264
2265        // "A: 1\r\n" is 6 bytes; with 8 the final CRLF still fits.
2266        let limits = Limits::new().with_max_header_bytes(8);
2267        let mut s = HeadScanner::new();
2268        assert!(
2269            s.advance(
2270                b"GET / HTTP/1.1\r\nA: 1\r\n\r\n",
2271                &limits,
2272                HeadKind::Request,
2273                true
2274            )
2275            .is_ok()
2276        );
2277        let mut s = HeadScanner::new();
2278        assert_eq!(
2279            s.advance(
2280                b"GET / HTTP/1.1\r\nA: 12\r\nB: 1\r\n\r\n",
2281                &limits,
2282                HeadKind::Request,
2283                true
2284            )
2285            .err(),
2286            Some(HttpError::HeadersTooLarge)
2287        );
2288    }
2289
2290    fn response(line: &[u8]) -> Result<ResponseInfo, HttpError> {
2291        let mut msg = line.to_vec();
2292        msg.extend_from_slice(b"\r\nContent-Length: 0\r\n\r\n");
2293        let (s, _) = scan(&msg, HeadKind::Response)?;
2294        interpret_response(
2295            &msg,
2296            s.start_line(),
2297            &s.fields,
2298            &Limits::new(),
2299            Asked {
2300                head: false,
2301                connect: false,
2302            },
2303        )
2304    }
2305
2306    #[test]
2307    fn test_status_line_without_space_after_code_is_accepted() {
2308        let info = response(b"HTTP/1.1 200").unwrap();
2309        assert_eq!(info.status, 200);
2310        assert_eq!(info.reason, Span::new(12, 12));
2311        assert_eq!(response(b"HTTP/1.1 200 ").unwrap().status, 200);
2312        assert_eq!(response(b"HTTP/1.1 204 No Content").unwrap().status, 204);
2313        assert_eq!(
2314            response(b"HTTP/1.1 20").err(),
2315            Some(HttpError::InvalidStartLine)
2316        );
2317        assert_eq!(
2318            response(b"HTTP/1.1 2000").err(),
2319            Some(HttpError::InvalidStartLine)
2320        );
2321        assert_eq!(
2322            response(b"HTTP/1.1200 OK").err(),
2323            Some(HttpError::InvalidStartLine)
2324        );
2325        assert_eq!(
2326            response(b"HTTP/1.1 600").err(),
2327            Some(HttpError::InvalidStatus)
2328        );
2329    }
2330
2331    #[test]
2332    fn test_protocol_matching_rules() {
2333        assert!(protocol_matches(b"websocket", b"websocket"));
2334        assert!(protocol_matches(b"WebSocket", b"websocket"));
2335        assert!(protocol_matches(b"websocket", b"websocket/13"));
2336        assert!(protocol_matches(b"foo/2", b"FOO/2"));
2337        assert!(!protocol_matches(b"foo/2", b"foo/3"));
2338        assert!(!protocol_matches(b"foo/2", b"foo"));
2339        assert!(!protocol_matches(b"ws", b"websocket"));
2340        assert!(!protocol_matches(b"h2c", b"h2c"));
2341        assert!(!protocol_matches(b"H2C", b"h2c"));
2342        assert!(is_h2c(b"h2c/1") && is_h2c(b"H2c") && !is_h2c(b"h2"));
2343    }
2344
2345    #[test]
2346    fn test_authority_targets_refuse_empty_host_and_bad_escapes() {
2347        assert!(check_target(Method::Connect, b"a%41:443").is_ok());
2348        assert!(check_target(Method::Connect, b"a%4:443").is_err());
2349        assert!(check_target(Method::Get, b"http://a%zz/").is_err());
2350        assert!(check_target(Method::Get, b"http://a%41b/").is_ok());
2351        assert!(check_target(Method::Get, b"ftp://h/").is_ok());
2352    }
2353
2354    #[test]
2355    fn test_versions() {
2356        assert_eq!(parse_version(b"HTTP/1.1"), Ok(Version::Http11));
2357        assert_eq!(parse_version(b"HTTP/1.0"), Ok(Version::Http10));
2358        assert_eq!(parse_version(b"HTTP/1.9"), Ok(Version::Http11));
2359        assert_eq!(
2360            parse_version(b"HTTP/2.0"),
2361            Err(HttpError::UnsupportedVersion)
2362        );
2363        assert_eq!(
2364            parse_version(b"HTTP/0.9"),
2365            Err(HttpError::UnsupportedVersion)
2366        );
2367        assert_eq!(parse_version(b"http/1.1"), Err(HttpError::InvalidVersion));
2368        assert_eq!(parse_version(b"HTTP/1.10"), Err(HttpError::InvalidVersion));
2369        assert_eq!(parse_version(b"HTTP/1"), Err(HttpError::InvalidVersion));
2370    }
2371
2372    #[test]
2373    fn test_target_forms_follow_method() {
2374        assert!(check_target(Method::Get, b"/").is_ok());
2375        assert!(check_target(Method::Options, b"*").is_ok());
2376        assert!(check_target(Method::Get, b"*").is_err());
2377        assert!(check_target(Method::Connect, b"example.com:443").is_ok());
2378        assert!(check_target(Method::Connect, b"[::1]:443").is_ok());
2379        assert!(check_target(Method::Connect, b"example.com").is_err());
2380        assert!(check_target(Method::Connect, b"/").is_err());
2381        assert!(check_target(Method::Get, b"http://example.com/a?b").is_ok());
2382        assert!(check_target(Method::Get, b"http://[::1]:80/").is_ok());
2383        assert!(check_target(Method::Get, b"http://x").is_ok());
2384        assert!(check_target(Method::Get, b"http://x?q").is_ok());
2385        assert!(check_target(Method::Get, b"http://u@x/").is_err());
2386        assert!(check_target(Method::Get, b"http:x").is_err());
2387        assert!(check_target(Method::Get, b"http://:80/").is_err());
2388        assert!(check_target(Method::Get, b"http://x/[a]").is_err());
2389        assert!(check_target(Method::Connect, b":443").is_err());
2390        assert!(check_target(Method::Get, b"1http://x").is_err());
2391        assert!(check_target(Method::Get, b"example.com").is_err());
2392        assert!(check_target(Method::Get, b"").is_err());
2393    }
2394}