Skip to main content

http_net/
head.rs

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