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