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