Skip to main content

ntex_httparse/
lib.rs

1#![deny(clippy::pedantic, clippy::missing_safety_doc)]
2#![allow(
3    clippy::cast_lossless,
4    clippy::cast_possible_truncation,
5    clippy::missing_panics_doc,
6    clippy::missing_errors_doc
7)]
8#![cfg_attr(not(any(test, feature = "std")), no_std)]
9#![cfg_attr(test, deny(warnings))]
10
11//! # ntex-httparse
12//!
13//! A push library for parsing HTTP/1.x requests and responses, used by
14//! [ntex](https://crates.io/crates/ntex). It is a fork of
15//! [httparse](https://crates.io/crates/httparse) with a lower level API.
16//!
17//! Parsers do not borrow the input. Parsed parts are returned as
18//! [`SlicePos`] ranges into the buffer passed to `parse`. The start line and
19//! the headers are parsed separately:
20//!
21//! * [`Request::parse`] or [`Response::parse`] parses the start line and
22//!   returns the position right after it.
23//! * [`Header::parse`] parses one header at a time, until it returns
24//!   [`HeaderParsed::Eof`] for the empty line ending the header section.
25//! * [`parse_chunk_size`] parses the size line of a chunked body.
26//!
27//! Incomplete input is not an error, the parsers return
28//! [`Status::Partial`]. The `parse_with_state` variants save their progress
29//! in a [`State`], so the next call with more data continues where the
30//! previous one stopped instead of starting over.
31//!
32//! The focus is on speed and safety. Parsing is bounds-checked, unsafe code
33//! is limited to the SIMD matchers in a submodule.
34//!
35//! SIMD optimizations are enabled automatically when available.
36//! If building an executable to be run on multiple platforms, and thus
37//! not passing `target_feature` or `target_cpu` flags to the compiler,
38//! runtime detection can still detect SSE4.2 or AVX2 support to provide
39//! massive wins.
40//!
41//! If compiling for a specific target, remembering to include
42//! `-C target_cpu=native` allows the detection to become compile time checks,
43//! making it *even* faster.
44//!
45//! # Example
46//!
47//! ```
48//! use ntex_httparse::{Header, HeaderParsed, Request, Status};
49//!
50//! let buf = b"GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\nbody";
51//!
52//! let mut req = Request::default();
53//! let Status::Complete(mut pos) = req.parse(buf).unwrap() else {
54//!     unreachable!("the request line is complete")
55//! };
56//! assert_eq!(&buf[req.path.start..req.path.end], b"/index.html");
57//! assert_eq!(req.version, 1);
58//!
59//! let mut header = Header::default();
60//! loop {
61//!     let src = &buf[pos..];
62//!     match header.parse(src).unwrap() {
63//!         Status::Complete(HeaderParsed::Header(len)) => {
64//!             assert_eq!(&src[header.name.start..header.name.end], b"Host");
65//!             assert_eq!(&src[header.value.start..header.value.end], b"example.com");
66//!             pos += len;
67//!         }
68//!         Status::Complete(HeaderParsed::Eof(len)) => {
69//!             pos += len;
70//!             break;
71//!         }
72//!         // wait for more data, then parse again
73//!         Status::Partial => unreachable!(),
74//!     }
75//! }
76//! assert_eq!(&buf[pos..], b"body");
77//! ```
78
79use core::{fmt, result, str};
80
81mod iter;
82#[macro_use]
83mod macros;
84mod headers;
85mod simd;
86mod utils;
87mod version;
88
89pub use crate::headers::{Header, HeaderParsed};
90pub use crate::version::parse_version;
91
92use crate::iter::Bytes;
93
94/// An error in parsing.
95#[derive(Copy, Clone, PartialEq, Eq, Debug)]
96pub enum Error {
97    /// Invalid byte in header name.
98    HeaderName,
99    /// Invalid byte in header value.
100    HeaderValue,
101    /// Invalid byte in new line.
102    NewLine,
103    /// Invalid byte in Response status.
104    Status,
105    /// Invalid byte where token is required.
106    Token,
107    /// Unused, kept for compatibility. Headers are parsed one at a time.
108    TooManyHeaders,
109    /// Invalid byte in HTTP version.
110    Version,
111}
112
113impl Error {
114    #[inline]
115    fn description_str(self) -> &'static str {
116        match self {
117            Error::HeaderName => "invalid header name",
118            Error::HeaderValue => "invalid header value",
119            Error::NewLine => "invalid new line",
120            Error::Status => "invalid response status",
121            Error::Token => "invalid token",
122            Error::TooManyHeaders => "too many headers",
123            Error::Version => "invalid HTTP version",
124        }
125    }
126}
127
128impl fmt::Display for Error {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.write_str(self.description_str())
131    }
132}
133
134#[cfg(feature = "std")]
135impl std::error::Error for Error {
136    fn description(&self) -> &str {
137        self.description_str()
138    }
139}
140
141/// An error in parsing a chunk size.
142#[derive(Debug, PartialEq, Eq)]
143pub struct InvalidChunkSize;
144
145impl fmt::Display for InvalidChunkSize {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        f.write_str("invalid chunk size")
148    }
149}
150
151/// A Result of any parsing action.
152///
153/// If the input is invalid, an `Error` will be returned. Note that incomplete
154/// data is not considered invalid, and so will not return an error, but rather
155/// a `Ok(Status::Partial)`.
156pub type Result<T> = result::Result<Status<T>, Error>;
157
158/// The result of a successful parse pass.
159///
160/// `Complete` is used when the buffer contained the complete value.
161/// `Partial` is used when parsing did not reach the end of the expected value,
162/// but no invalid data was found.
163#[derive(Copy, Clone, Eq, PartialEq, Debug)]
164pub enum Status<T> {
165    /// The completed result.
166    Complete(T),
167    /// A partial result.
168    Partial,
169}
170
171impl<T> Status<T> {
172    /// Convenience method to check if status is complete.
173    #[inline]
174    pub fn is_complete(&self) -> bool {
175        match *self {
176            Status::Complete(..) => true,
177            Status::Partial => false,
178        }
179    }
180
181    /// Convenience method to check if status is partial.
182    #[inline]
183    pub fn is_partial(&self) -> bool {
184        match *self {
185            Status::Complete(..) => false,
186            Status::Partial => true,
187        }
188    }
189
190    /// Convenience method to unwrap a Complete value. Panics if the status is
191    /// `Partial`.
192    #[inline]
193    pub fn unwrap(self) -> T {
194        match self {
195            Status::Complete(t) => t,
196            Status::Partial => panic!("Tried to unwrap Status::Partial"),
197        }
198    }
199}
200
201/// Progress of a resumable parse, used by the `parse_with_state` methods.
202///
203/// Start with `State::default()` and pass the same `State` again, with the
204/// same (possibly grown) buffer, after a [`Status::Partial`] result. Reset it
205/// to default before parsing the next item from a different buffer position.
206/// The fields are internal bookkeeping and should not be changed by callers.
207#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
208pub struct State {
209    /// Parser specific step.
210    pub state: u8,
211    /// Start of the part being parsed.
212    pub start: usize,
213    /// Position of the next byte to parse.
214    pub cursor: usize,
215}
216
217#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
218/// A range of the buffer passed to `parse`, i.e. `&src[pos.start..pos.end]`.
219///
220/// An empty part, like an empty header value or reason phrase, is `0..0`.
221pub struct SlicePos {
222    /// Start of the range, inclusive.
223    pub start: usize,
224    /// End of the range, exclusive.
225    pub end: usize,
226}
227
228impl SlicePos {
229    pub(crate) fn reset(&mut self) {
230        self.start = 0;
231        self.end = 0;
232    }
233}
234
235/// A parsed request line.
236///
237/// Only the request line is parsed, use [`Header`] for the headers that
238/// follow it.
239///
240/// # Example
241///
242/// ```
243/// use ntex_httparse::{Request, State, Status};
244///
245/// let mut req = Request::default();
246/// let mut st = State::default();
247///
248/// // incomplete data, the parser remembers its progress in `st`
249/// let buf = b"GET /index.html HT";
250/// assert_eq!(req.parse_with_state(buf, &mut st), Ok(Status::Partial));
251///
252/// let buf = b"GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n";
253/// assert_eq!(req.parse_with_state(buf, &mut st), Ok(Status::Complete(26)));
254/// assert_eq!(&buf[req.method.start..req.method.end], b"GET");
255/// assert_eq!(&buf[req.path.start..req.path.end], b"/index.html");
256/// ```
257#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
258pub struct Request {
259    /// Request method, an ASCII token.
260    pub method: SlicePos,
261    /// Request target. May contain bytes `0x80..=0xFF`, so it is not
262    /// guaranteed to be UTF-8.
263    pub path: SlicePos,
264    /// `true` if the request target contains only ASCII bytes, so it is valid
265    /// UTF-8 and needs no further UTF-8 check.
266    pub path_ascii: bool,
267    /// Position of the first `?` in the request target, an index into the
268    /// parsed buffer like `path`, `None` if the target has no query.
269    pub query: Option<usize>,
270    /// HTTP version, `0` for HTTP/1.0 and `1` for HTTP/1.1.
271    pub version: u8,
272}
273
274impl Request {
275    #[inline]
276    /// Parse a request line.
277    ///
278    /// Returns the position right after the line ending, where the headers
279    /// start. Empty lines before the request line are skipped.
280    pub fn parse(&mut self, src: &[u8]) -> Result<usize> {
281        let mut st = State::default();
282        self.parse_with_state(src, &mut st)
283    }
284
285    #[inline]
286    /// Parse a request line, resuming from `st` saved by a previous `Partial`
287    /// result.
288    ///
289    /// `st` must come from a previous call with the same buffer (which may have
290    /// grown since), or be `State::default()`. An invalid state returns
291    /// `Error::Token`.
292    ///
293    /// Bytes accepted by earlier calls are not scanned again, so feeding the
294    /// line in pieces takes linear time.
295    pub fn parse_with_state(&mut self, src: &[u8], st: &mut State) -> Result<usize> {
296        const EMPTY_LINES: u8 = 0;
297        const METHOD: u8 = 1;
298        const SPACES_BEFORE_URI: u8 = 2;
299        const URI: u8 = 3;
300        const SPACES_BEFORE_VERSION: u8 = 4;
301        const VERSION: u8 = 5;
302        const NEWLINE: u8 = 6;
303
304        if st.state > NEWLINE || st.start > st.cursor || st.cursor > src.len() {
305            return Err(Error::Token);
306        }
307        let mut bytes = Bytes::new(src, st);
308
309        if bytes.st.state == EMPTY_LINES {
310            complete!(utils::skip_empty_lines(&mut bytes));
311            bytes.st.state = METHOD;
312        }
313        if bytes.st.state == METHOD {
314            self.method = complete!(parse_method_inner(&mut bytes));
315            bytes.st.state = SPACES_BEFORE_URI;
316        }
317        if bytes.st.state == SPACES_BEFORE_URI {
318            complete!(utils::skip_spaces(&mut bytes));
319            self.path_ascii = true;
320            self.query = None;
321            bytes.st.state = URI;
322        }
323        if bytes.st.state == URI {
324            self.path = complete!(parse_target_inner(
325                &mut bytes,
326                &mut self.query,
327                &mut self.path_ascii
328            ));
329            bytes.st.state = SPACES_BEFORE_VERSION;
330        }
331        if bytes.st.state == SPACES_BEFORE_VERSION {
332            complete!(utils::skip_spaces(&mut bytes));
333            bytes.st.state = VERSION;
334        }
335        if bytes.st.state == VERSION {
336            // at most 8 bytes, parsed again from the start if incomplete
337            let mut tmp = *bytes.st;
338            self.version = complete!(version::parse_version_inner(&mut Bytes::new(src, &mut tmp)));
339            *bytes.st = tmp;
340            bytes.st.state = NEWLINE;
341        }
342
343        newline!(bytes);
344        Ok(Status::Complete(bytes.cursor()))
345    }
346}
347
348/// A parsed status line.
349///
350/// Only the status line is parsed, use [`Header`] for the headers that
351/// follow it.
352///
353/// # Example
354///
355/// ```
356/// use ntex_httparse::{Response, Status};
357///
358/// let buf = b"HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
359/// let mut res = Response::default();
360/// assert_eq!(res.parse(buf), Ok(Status::Complete(24)));
361/// assert_eq!(res.code, 404);
362/// assert_eq!(&buf[res.reason.start..res.reason.end], b"Not Found");
363/// ```
364#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
365pub struct Response {
366    /// HTTP version, `0` for HTTP/1.0 and `1` for HTTP/1.1.
367    pub version: u8,
368    /// Status code, three digits.
369    pub code: u16,
370    /// Reason phrase, empty if missing. A non-empty reason is ASCII, a reason
371    /// containing obs-text (bytes `0x80..=0xFF`) is returned as empty.
372    pub reason: SlicePos,
373}
374
375impl Response {
376    #[inline]
377    /// Parse a status line.
378    ///
379    /// Returns the position right after the line ending, where the headers
380    /// start. Empty lines before the status line are skipped. The reason
381    /// phrase is optional.
382    pub fn parse(&mut self, src: &[u8]) -> Result<usize> {
383        let mut st = State::default();
384        self.parse_with_state(src, &mut st)
385    }
386
387    #[inline]
388    /// Parse a status line, resuming from `st` saved by a previous `Partial`
389    /// result.
390    ///
391    /// `st` must come from a previous call with the same buffer (which may have
392    /// grown since), or be `State::default()`. An invalid state returns
393    /// `Error::Status`.
394    ///
395    /// Bytes accepted by earlier calls are not scanned again, so feeding the
396    /// line in pieces takes linear time.
397    pub fn parse_with_state(&mut self, src: &[u8], st: &mut State) -> Result<usize> {
398        const EMPTY_LINES: u8 = 0;
399        const VERSION: u8 = 1;
400        const SPACES_BEFORE_CODE: u8 = 2;
401        const CODE: u8 = 3;
402        const AFTER_CODE: u8 = 4;
403        const SPACES_BEFORE_REASON: u8 = 5;
404        const REASON: u8 = 6;
405        const REASON_OBS_TEXT: u8 = 7;
406
407        if st.state > REASON_OBS_TEXT || st.start > st.cursor || st.cursor > src.len() {
408            return Err(Error::Status);
409        }
410        let mut bytes = Bytes::new(src, st);
411
412        if bytes.st.state == EMPTY_LINES {
413            complete!(utils::skip_empty_lines(&mut bytes));
414            bytes.st.state = VERSION;
415        }
416        if bytes.st.state == VERSION {
417            // at most 9 bytes, parsed again from the start if incomplete
418            let mut tmp = *bytes.st;
419            let mut b = Bytes::new(src, &mut tmp);
420            self.version = complete!(version::parse_version_inner(&mut b));
421            expect!(b.next() == b' ' => Err(Error::Version));
422            b.commit();
423            *bytes.st = tmp;
424            bytes.st.state = SPACES_BEFORE_CODE;
425        }
426        if bytes.st.state == SPACES_BEFORE_CODE {
427            complete!(utils::skip_spaces(&mut bytes));
428            bytes.st.state = CODE;
429        }
430        if bytes.st.state == CODE {
431            // 3 bytes, parsed again from the start if incomplete
432            let mut tmp = *bytes.st;
433            self.code = complete!(parse_code(&mut Bytes::new(src, &mut tmp)));
434            *bytes.st = tmp;
435            bytes.st.state = AFTER_CODE;
436        }
437        if bytes.st.state == AFTER_CODE {
438            // RFC7230 says there must be 'SP' and then reason-phrase, but admits
439            // its only for legacy reasons. With the reason-phrase completely
440            // optional (and preferred to be omitted) in HTTP2, we'll just
441            // handle any response that doesn't include a reason-phrase, because
442            // it's more lenient, and we don't care anyways.
443            //
444            // So, a SP means parse a reason-phrase.
445            // A newline means go to headers.
446            // Anything else we'll say is a malformed status.
447            match next!(bytes) {
448                b' ' => bytes.st.state = SPACES_BEFORE_REASON,
449                b'\r' => {
450                    expect_lf!(bytes => Err(Error::Status));
451                    bytes.commit();
452                    self.reason = SlicePos::default();
453                    return Ok(Status::Complete(bytes.cursor()));
454                }
455                b'\n' => {
456                    bytes.commit();
457                    self.reason = SlicePos::default();
458                    return Ok(Status::Complete(bytes.cursor()));
459                }
460                _ => return Err(Error::Status),
461            }
462        }
463        if bytes.st.state == SPACES_BEFORE_REASON {
464            complete!(utils::skip_spaces(&mut bytes));
465            bytes.st.state = REASON;
466        }
467
468        let mut seen_obs_text = bytes.st.state == REASON_OBS_TEXT;
469        let res = parse_reason(&mut bytes, &mut seen_obs_text);
470        if seen_obs_text {
471            bytes.st.state = REASON_OBS_TEXT;
472        }
473        self.reason = complete!(res);
474        Ok(Status::Complete(bytes.cursor()))
475    }
476}
477
478#[inline]
479#[doc(hidden)]
480/// Parse a request method. Exported for internal benchmarks, not part of the
481/// public API.
482pub fn parse_method(src: &[u8]) -> Result<&str> {
483    let mut st = State::default();
484    let mut bytes = Bytes::new(src, &mut st);
485    complete!(utils::skip_empty_lines(&mut bytes));
486    let s = complete!(parse_method_inner(&mut bytes));
487    // SAFETY: parse_method_inner verifies validity of method
488    let m = unsafe { str::from_utf8_unchecked(&src[s.start..s.end]) };
489    Ok(Status::Complete(m))
490}
491
492/// Parses a method followed by a space, starting at `bytes.start()`. Bytes
493/// before the cursor were accepted by a previous call.
494#[inline]
495fn parse_method_inner(bytes: &mut Bytes<'_, '_>) -> Result<SlicePos> {
496    const GET: [u8; 4] = *b"GET ";
497    const POST: [u8; 4] = *b"POST";
498
499    if bytes.cursor() == bytes.start() {
500        match bytes.peek_n::<4>() {
501            Some(GET) => {
502                // we matched "GET " which has 4 bytes and is ASCII
503                bytes.advance(4);
504                return Ok(Status::Complete(bytes.slice_position(1)));
505            }
506            Some(POST) if bytes.peek_ahead(4) == Some(b' ') => {
507                // we matched "POST " which has 5 bytes
508                bytes.advance(5);
509                return Ok(Status::Complete(bytes.slice_position(1)));
510            }
511            _ => {}
512        }
513        // First char must be a token char, it can't be a space which would
514        // indicate an empty token.
515        if !utils::is_method_token(next!(bytes)) {
516            return Err(Error::Token);
517        }
518    }
519
520    loop {
521        let b = next!(bytes);
522        if b == b' ' {
523            // all bytes are `is_method_token`, so the method is ASCII
524            return Ok(Status::Complete(bytes.slice_position(1)));
525        } else if !utils::is_method_token(b) {
526            return Err(Error::Token);
527        }
528    }
529}
530
531/// From [RFC 7230](https://tools.ietf.org/html/rfc7230):
532///
533/// > ```notrust
534/// > reason-phrase  = *( HTAB / SP / VCHAR / obs-text )
535/// > HTAB           = %x09        ; horizontal tab
536/// > VCHAR          = %x21-7E     ; visible (printing) characters
537/// > obs-text       = %x80-FF
538/// > ```
539///
540/// > A.2.  Changes from RFC 2616
541/// >
542/// > Non-US-ASCII content in header fields and the reason phrase
543/// > has been obsoleted and made opaque (the TEXT rule was removed).
544///
545/// Parses from `bytes.start()`, bytes before the cursor were accepted by a
546/// previous call, `seen_obs_text` carries over whether they had obs-text.
547#[inline]
548fn parse_reason(bytes: &mut Bytes<'_, '_>, seen_obs_text: &mut bool) -> Result<SlicePos> {
549    // Short reasons are scanned byte by byte, the SIMD call only pays off
550    // for longer ones. Reason bytes are the same set as header value bytes.
551    const SCALAR_PREFIX: usize = 8;
552    let mut n = 0;
553    while let Some(b) = bytes.peek() {
554        if n == SCALAR_PREFIX {
555            if !matches!(b, b'\r' | b'\n') {
556                match_reason_vectored(bytes, seen_obs_text);
557            }
558            break;
559        }
560        if utils::is_header_value_token(b) {
561            if b >= 0x80 {
562                *seen_obs_text = true;
563            }
564            bytes.advance(1);
565            n += 1;
566        } else {
567            break;
568        }
569    }
570
571    loop {
572        let b = next!(bytes);
573        let skip = if b == b'\r' {
574            expect_lf!(bytes => Err(Error::Status));
575            2
576        } else if b == b'\n' {
577            1
578        } else if !(b == 0x09 || b == b' ' || (0x21..=0x7E).contains(&b) || b >= 0x80) {
579            return Err(Error::Status);
580        } else {
581            if b >= 0x80 {
582                *seen_obs_text = true;
583            }
584            continue;
585        };
586
587        // A non-empty reason contains only HTAB / SP / VCHAR, so it is
588        // ASCII. With obs-text an empty reason is returned instead.
589        let reason = bytes.slice_position(skip);
590        return Ok(Status::Complete(
591            if *seen_obs_text || reason.start == reason.end {
592                SlicePos::default()
593            } else {
594                reason
595            },
596        ));
597    }
598}
599
600#[inline(never)]
601fn match_reason_vectored(bytes: &mut Bytes<'_, '_>, seen_obs_text: &mut bool) {
602    let from = bytes.cursor();
603    simd::match_header_value_vectored(bytes);
604    if !*seen_obs_text {
605        let scanned = bytes.since(from);
606        // Keep the tail separate so is_ascii uses word checks rather than
607        // a byte-at-a-time remainder after its vector loop.
608        let (blocks, tail) = scanned.split_at(scanned.len() & !63);
609        if !blocks.is_ascii() || !tail.is_ascii() {
610            *seen_obs_text = true;
611        }
612    }
613}
614
615#[inline]
616#[doc(hidden)]
617/// Parse a request target followed by a space. Exported for internal
618/// benchmarks, not part of the public API.
619///
620/// Unlike [`Request::parse`], returns `Error::Token` if the target is not
621/// valid UTF-8.
622pub fn parse_uri(src: &[u8]) -> Result<&str> {
623    let mut st = State::default();
624    let mut bytes = Bytes::new(src, &mut st);
625    if let Status::Complete(pos) = parse_uri_inner(&mut bytes)? {
626        if let Ok(path) = simdutf8::basic::from_utf8(&src[pos.start..pos.end]) {
627            Ok(Status::Complete(path))
628        } else {
629            Err(Error::Token)
630        }
631    } else {
632        Ok(Status::Partial)
633    }
634}
635
636#[inline]
637fn parse_uri_inner(bytes: &mut Bytes<'_, '_>) -> Result<SlicePos> {
638    let start = bytes.start();
639    simd::match_uri_vectored(bytes);
640    let b_end = bytes.cursor();
641
642    if next!(bytes) == b' ' {
643        // URI must have at least one char
644        if start == b_end {
645            return Err(Error::Token);
646        }
647
648        // URI bytes may include 0x80..=0xFF, so they are not guaranteed to be UTF-8
649        let end = bytes.cursor() - 1;
650        bytes.commit();
651        Ok(Status::Complete(SlicePos { start, end }))
652    } else {
653        Err(Error::Token)
654    }
655}
656
657/// Parses a request target like [`parse_uri_inner`], and records whether it
658/// is ASCII and where its query starts.
659///
660/// `ascii` and `query` must be `true` and `None` when the target starts, and
661/// are kept between `Partial` results, so a resumed scan does not start over.
662#[inline]
663fn parse_target_inner(
664    bytes: &mut Bytes<'_, '_>,
665    query: &mut Option<usize>,
666    ascii: &mut bool,
667) -> Result<SlicePos> {
668    let start = bytes.start();
669    // the ASCII scans stop at the first `?` and the first high byte, a
670    // non-ASCII target is finished with the plain scan
671    loop {
672        if !*ascii {
673            simd::match_uri_vectored(bytes);
674            break;
675        }
676        if query.is_none() {
677            simd::match_uri_ascii_vectored::<true>(bytes);
678        } else {
679            simd::match_uri_ascii_vectored::<false>(bytes);
680        }
681        match bytes.peek() {
682            Some(b'?') if query.is_none() => {
683                *query = Some(bytes.cursor());
684                bytes.advance(1);
685            }
686            Some(b) if b >= 0x80 => *ascii = false,
687            _ => break,
688        }
689    }
690    let end = bytes.cursor();
691
692    if next!(bytes) == b' ' {
693        // URI must have at least one char
694        if start == end {
695            return Err(Error::Token);
696        }
697        // the plain scan does not stop at `?`
698        if !*ascii && query.is_none() {
699            *query = bytes
700                .since(start)
701                .iter()
702                .position(|&b| b == b'?')
703                .map(|i| start + i);
704        }
705        bytes.commit();
706        Ok(Status::Complete(SlicePos { start, end }))
707    } else {
708        Err(Error::Token)
709    }
710}
711
712#[inline]
713fn parse_code(bytes: &mut Bytes<'_, '_>) -> Result<u16> {
714    let hundreds = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
715    let tens = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
716    let ones = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
717
718    Ok(Status::Complete(
719        (hundreds - b'0') as u16 * 100 + (tens - b'0') as u16 * 10 + (ones - b'0') as u16,
720    ))
721}
722
723/// Parse a buffer of bytes as a chunk size line.
724///
725/// The return value, if complete and successful, includes the position right
726/// after the line, where the chunk data starts, and the size of the chunk.
727/// A size of `0` is the last chunk.
728///
729/// The size is 1 to 16 hex digits and the line must end with CRLF. Chunk
730/// extensions are skipped, control characters other than HTAB are rejected
731/// in them.
732///
733/// # Example
734///
735/// ```
736/// let buf = b"4\r\nRust\r\n0\r\n\r\n";
737/// assert_eq!(ntex_httparse::parse_chunk_size(buf),
738///            Ok(ntex_httparse::Status::Complete((3, 4))));
739/// ```
740pub fn parse_chunk_size(buf: &[u8]) -> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
741    const RADIX: u64 = 16;
742    let mut st = State::default();
743    let mut bytes = Bytes::new(buf, &mut st);
744    let mut size = 0;
745    let mut in_chunk_size = true;
746    let mut in_ext = false;
747    let mut count = 0;
748    loop {
749        let b = next!(bytes);
750        match b {
751            b'0'..=b'9' if in_chunk_size => {
752                if count > 15 {
753                    return Err(InvalidChunkSize);
754                }
755                count += 1;
756                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
757                    // actually unreachable!(), because count stops the loop at 15 digits before
758                    // we can reach u64::MAX / RADIX == 0xfffffffffffffff, which requires 15 hex
759                    // digits. This stops mirai reporting a false alarm regarding the `size *=
760                    // RADIX` multiplication below.
761                    return Err(InvalidChunkSize);
762                }
763                size *= RADIX;
764                size += (b - b'0') as u64;
765            }
766            b'a'..=b'f' | b'A'..=b'F' if in_chunk_size => {
767                if count > 15 {
768                    return Err(InvalidChunkSize);
769                }
770                count += 1;
771                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
772                    return Err(InvalidChunkSize);
773                }
774                size *= RADIX;
775                size += ((b | 0x20) + 10 - b'a') as u64;
776            }
777            // the chunk size must have at least one digit
778            b'\r' if count == 0 => return Err(InvalidChunkSize),
779            b'\r' => match next!(bytes) {
780                b'\n' => break,
781                _ => return Err(InvalidChunkSize),
782            },
783            // If we weren't in the extension yet, the ";" signals its start
784            b';' if !in_ext => {
785                in_ext = true;
786                in_chunk_size = false;
787            }
788            // "Linear white space" is ignored between the chunk size and the
789            // extension separator token (";") due to the "implied *LWS rule".
790            b'\t' | b' ' if !in_ext && !in_chunk_size => {}
791            // LWS can follow the chunk size, but no more digits can come
792            b'\t' | b' ' if in_chunk_size => in_chunk_size = false,
793            // Control characters other than HTAB are not allowed in extensions,
794            // a bare LF could be treated as the line end by other parsers.
795            0x00..=0x08 | 0x0a..=0x1f | 0x7f if in_ext => return Err(InvalidChunkSize),
796            // We allow any other octet once we are in the extension, since
797            // they all get ignored anyway. According to the HTTP spec, valid
798            // extensions would have a more strict syntax:
799            //     (token ["=" (token | quoted-string)])
800            // but we gain nothing by rejecting an otherwise valid chunk size.
801            _ if in_ext => {}
802            // Finally, if we aren't in the extension and we're reading any
803            // other octet, the chunk size line is invalid!
804            _ => return Err(InvalidChunkSize),
805        }
806    }
807    Ok(Status::Complete((bytes.cursor(), size)))
808}
809
810#[cfg(test)]
811mod tests {
812    #![allow(clippy::items_after_statements)]
813    use super::*;
814
815    macro_rules! req {
816        ($name:ident, $buf:expr, |$len:ident, $method:ident, $path:ident, $version:ident, $headers:ident, $headers_eof:ident| $body:expr) => {
817            #[test]
818            fn $name() {
819                let mut req = Request::default();
820                let mut b = $buf.as_ref();
821                if let Ok(Status::Complete(l)) = req.parse(b) {
822                    let mut consumed = l;
823                    let mut headers = Vec::new();
824                    let mut header = Header::default();
825                    let mut headers_eof = false;
826                    b = &b[consumed..];
827
828                    while let Status::Complete(hdr) = header.parse(b).unwrap() {
829                        match hdr {
830                            HeaderParsed::Header(l) => {
831                                consumed += l;
832                                let name = String::from_utf8(Vec::from(
833                                    &b[header.name.start..header.name.end],
834                                ))
835                                .unwrap();
836                                let value = Vec::from(&b[header.value.start..header.value.end]);
837                                headers.push((name, value));
838                                b = &b[l..];
839                            }
840                            HeaderParsed::Eof(l) => {
841                                consumed += l;
842                                headers_eof = true;
843                                break;
844                            }
845                        }
846                    }
847
848                    // SAFETY: Request::parse() validates path
849                    let (path, method) = unsafe {
850                        (
851                            str::from_utf8_unchecked(&$buf.as_ref()[req.path.start..req.path.end]),
852                            str::from_utf8_unchecked(
853                                &$buf.as_ref()[req.method.start..req.method.end],
854                            ),
855                        )
856                    };
857
858                    closure(consumed, method, path, req.version, headers, headers_eof);
859                } else {
860                    panic!()
861                }
862
863                fn closure(
864                    $len: usize,
865                    $method: &str,
866                    $path: &str,
867                    $version: u8,
868                    $headers: Vec<(String, Vec<u8>)>,
869                    $headers_eof: bool,
870                ) {
871                    $body
872                }
873            }
874        };
875    }
876
877    macro_rules! headers {
878        ($name:ident, $buf:expr, |$len:ident, $headers:ident, $headers_eof:ident| $body:expr) => {
879            #[test]
880            fn $name() {
881                let mut b = $buf.as_ref();
882                let mut consumed = 0;
883                let mut headers = Vec::new();
884                let mut header = Header::default();
885                let mut headers_eof = false;
886
887                while let Status::Complete(hdr) = header.parse(b).unwrap() {
888                    match hdr {
889                        HeaderParsed::Header(l) => {
890                            consumed += l;
891                            let name = String::from_utf8(Vec::from(
892                                &b[header.name.start..header.name.end],
893                            ))
894                            .unwrap();
895                            let value = Vec::from(&b[header.value.start..header.value.end]);
896                            headers.push((name, value));
897                            b = &b[l..];
898                        }
899                        HeaderParsed::Eof(l) => {
900                            consumed += l;
901                            headers_eof = true;
902                            break;
903                        }
904                    }
905                }
906                closure(consumed, headers, headers_eof);
907
908                fn closure($len: usize, $headers: Vec<(String, Vec<u8>)>, $headers_eof: bool) {
909                    $body
910                }
911            }
912        };
913    }
914
915    macro_rules! req_err {
916        ($name:ident, $buf:expr, $err:expr) => {
917            #[test]
918            fn $name() {
919                assert_eq!(Request::default().parse($buf.as_ref()), $err);
920            }
921        };
922    }
923
924    macro_rules! req_par {
925        ($name:ident, $buf:expr) => {
926            #[test]
927            fn $name() {
928                assert_eq!(Request::default().parse($buf.as_ref()), Ok(Status::Partial));
929            }
930        };
931    }
932
933    macro_rules! headers_err {
934        ($name:ident, $buf:expr, $err:expr) => {
935            #[test]
936            fn $name() {
937                let mut consumed = 0;
938                let mut header = Header::default();
939
940                let result = loop {
941                    match header.parse(&$buf.as_ref()[consumed..]) {
942                        Ok(Status::Complete(HeaderParsed::Header(l))) => {
943                            consumed += l;
944                        }
945                        Ok(_) => break Ok(()),
946                        Err(e) => break Err(e),
947                    }
948                };
949                assert_eq!(result, $err);
950            }
951        };
952    }
953
954    req! {
955        test_request_simple,
956        b"GET / HTTP/1.1\r\n\r\n",
957        |len, method, path, version, headers, eof| {
958            assert_eq!(len, 18);
959            assert_eq!(method, "GET");
960            assert_eq!(path, "/");
961            assert_eq!(version, 1);
962            assert_eq!(headers.len(), 0);
963            assert!(eof);
964        }
965    }
966
967    req! {
968        test_request_simple_with_query_params,
969        b"GET /thing?data=a HTTP/1.1\r\n\r\n",
970        |len, method, path, version, headers, eof| {
971            assert_eq!(len, 30);
972            assert_eq!(method, "GET");
973            assert_eq!(path, "/thing?data=a");
974            assert_eq!(version, 1);
975            assert_eq!(headers.len(), 0);
976            assert!(eof);
977        }
978    }
979
980    req! {
981        test_request_simple_with_whatwg_query_params,
982        b"GET /thing?data=a^ HTTP/1.1\r\n\r\n",
983        |len, method, path, version, headers, eof| {
984            assert_eq!(len, 31);
985            assert_eq!(method, "GET");
986            assert_eq!(path, "/thing?data=a^");
987            assert_eq!(version, 1);
988            assert_eq!(headers.len(), 0);
989            assert!(eof);
990        }
991    }
992
993    req! {
994        test_request_headers,
995        b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n     ",
996        |len, method, path, version, headers, eof| {
997            assert_eq!(len, 43);
998            assert_eq!(method, "GET");
999            assert_eq!(path, "/");
1000            assert_eq!(version, 1);
1001            assert_eq!(headers.len(), 2);
1002            assert_eq!(headers[0].0, "Host");
1003            assert_eq!(headers[0].1, b"foo.com");
1004            assert_eq!(headers[1].0, "Cookie");
1005            assert_eq!(headers[1].1, b"");
1006            assert!(eof);
1007        }
1008    }
1009
1010    req! {
1011        test_request_headers_optional_whitespace,
1012        b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n",
1013        |len, method, path, version, headers, eof| {
1014            assert_eq!(len, 48);
1015            assert_eq!(method, "GET");
1016            assert_eq!(path, "/");
1017            assert_eq!(version, 1);
1018            assert_eq!(headers.len(), 2);
1019            assert_eq!(headers[0].0, "Host");
1020            assert_eq!(headers[0].1, b"foo.com");
1021            assert_eq!(headers[1].0, "Cookie");
1022            assert_eq!(headers[1].1, b"");
1023            assert!(eof);
1024        }
1025    }
1026
1027    req! {
1028        // test the scalar parsing
1029        test_request_header_value_htab_short,
1030        b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n",
1031        |len, method, path, version, headers, eof| {
1032            assert_eq!(len, 42);
1033            assert_eq!(method, "GET");
1034            assert_eq!(path, "/");
1035            assert_eq!(version, 1);
1036            assert_eq!(headers.len(), 1);
1037            assert_eq!(headers[0].0, "User-Agent");
1038            assert_eq!(headers[0].1, b"some\tagent");
1039            assert!(eof);
1040        }
1041    }
1042
1043    req! {
1044        // test the sse42 parsing
1045        test_request_header_value_htab_med,
1046        b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n",
1047        |len, method, path, version, headers, eof| {
1048            assert_eq!(len, 52);
1049            assert_eq!(method, "GET");
1050            assert_eq!(path, "/");
1051            assert_eq!(version, 1);
1052            assert_eq!(headers.len(), 1);
1053            assert_eq!(headers[0].0, "User-Agent");
1054            assert_eq!(headers[0].1, b"1234567890some\tagent");
1055            assert!(eof);
1056        }
1057    }
1058
1059    req! {
1060        // test the avx2 parsing
1061        test_request_header_value_htab_long,
1062        b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n",
1063        |len, method, path, version, headers, eof| {
1064            assert_eq!(len, 72);
1065            assert_eq!(method, "GET");
1066            assert_eq!(path, "/");
1067            assert_eq!(version, 1);
1068            assert_eq!(headers.len(), 1);
1069            assert_eq!(headers[0].0, "User-Agent");
1070            assert_eq!(headers[0].1, &b"1234567890some\t1234567890agent1234567890"[..]);
1071            assert!(eof);
1072        }
1073    }
1074
1075    req! {
1076        // test the avx2 parsing
1077        test_request_header_no_space_after_colon,
1078        b"GET / HTTP/1.1\r\nUser-Agent:omg-no-space1234567890some1234567890agent1234567890\r\n\r\n",
1079        |len, method, path, version, headers, eof| {
1080            assert_eq!(len, 82);
1081            assert_eq!(method, "GET");
1082            assert_eq!(path, "/");
1083            assert_eq!(version, 1);
1084            assert_eq!(headers.len(), 1);
1085            assert_eq!(headers[0].0, "User-Agent");
1086            assert_eq!(headers[0].1, &b"omg-no-space1234567890some1234567890agent1234567890"[..]);
1087            assert!(eof);
1088        }
1089    }
1090
1091    req! {
1092        test_request_headers_max,
1093        b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n",
1094        |_len, _method, _path, _verion, headers, eof| {
1095            assert_eq!(headers.len(), 4);
1096            assert!(eof);
1097        }
1098    }
1099
1100    req! {
1101        test_request_multibyte,
1102        b"GET / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\n\r\n",
1103        |len, method, path, version, headers, eof| {
1104            assert_eq!(len, 55);
1105            assert_eq!(method, "GET");
1106            assert_eq!(path, "/");
1107            assert_eq!(version, 1);
1108            assert_eq!(headers.len(), 2);
1109            assert_eq!(headers[0].0, "Host");
1110            assert_eq!(headers[0].1, b"foo.com");
1111            assert_eq!(headers[1].0, "User-Agent");
1112            assert_eq!(headers[1].1, b"\xe3\x81\xb2\xe3/1.0");
1113            assert!(eof);
1114        }
1115    }
1116
1117    // A single byte which is part of a method is not invalid
1118    req_par! {
1119        test_request_one_byte_method,
1120        b"G"
1121    }
1122
1123    // A subset of a method is a partial method, not invalid
1124    req_par! {
1125        test_request_partial_method,
1126        b"GE"
1127    }
1128
1129    // A method, without the delimiting space, is a partial request
1130    req_par! {
1131        test_request_method_no_delimiter,
1132        b"GET"
1133    }
1134
1135    // Regression test: assert that a partial read with just the method and
1136    // space results in a partial, rather than a token error from uri parsing.
1137    req_par! {
1138        test_request_method_only,
1139        b"GET "
1140    }
1141
1142    req! {
1143        test_request_partial,
1144        b"GET / HTTP/1.1\r\n\r",
1145        |len, method, path, version, headers, eof| {
1146            assert_eq!(len, b"GET / HTTP/1.1\r\n\r".len() - 1);
1147            assert_eq!(method, "GET");
1148            assert_eq!(path, "/");
1149            assert_eq!(version, 1);
1150            assert_eq!(headers.len(), 0);
1151            assert!(!eof);
1152        }
1153    }
1154
1155    req_par! {
1156        test_request_partial_version,
1157        b"GET / HTTP/1."
1158    }
1159
1160    req_par! {
1161        test_request_method_path_no_delimiter,
1162        b"GET /"
1163    }
1164
1165    req_par! {
1166        test_request_method_path_only,
1167        b"GET / "
1168    }
1169
1170    req! {
1171        test_request_partial_parses_headers_as_much_as_it_can,
1172        b"GET / HTTP/1.1\r\nHost: yolo\r\n",
1173        |len, method, path, version, headers, eof| {
1174            assert_eq!(len, 28);
1175            assert_eq!(method, "GET");
1176            assert_eq!(path, "/");
1177            assert_eq!(version, 1);
1178            assert_eq!(headers.len(), 1);
1179            assert_eq!(headers[0].0, "Host");
1180            assert_eq!(headers[0].1, b"yolo");
1181            assert!(!eof);
1182        }
1183    }
1184
1185    req! {
1186        test_request_newlines,
1187        b"GET / HTTP/1.1\nHost: foo.bar\n\n",
1188        |_len, _method, _path, _verion, _headers, eof| {
1189            assert!(eof);
1190        }
1191    }
1192
1193    req! {
1194        test_request_empty_lines_prefix,
1195        b"\r\n\r\nGET / HTTP/1.1\r\n\r\n",
1196        |len, method, path, version, headers, eof| {
1197            assert_eq!(len, 22);
1198            assert_eq!(method, "GET");
1199            assert_eq!(path, "/");
1200            assert_eq!(version, 1);
1201            assert_eq!(headers.len(), 0);
1202            assert!(eof);
1203        }
1204    }
1205
1206    req! {
1207        test_request_empty_lines_prefix_lf_only,
1208        b"\n\nGET / HTTP/1.1\n\n",
1209        |len, method, path, version, headers, eof| {
1210            assert_eq!(len, 18);
1211            assert_eq!(method, "GET");
1212            assert_eq!(path, "/");
1213            assert_eq!(version, 1);
1214            assert_eq!(headers.len(), 0);
1215            assert!(eof);
1216        }
1217    }
1218
1219    req! {
1220        test_request_path_backslash,
1221        b"\n\nGET /\\?wayne\\=5 HTTP/1.1\n\n",
1222        |len, method, path, version, headers, eof| {
1223            assert_eq!(len, 28);
1224            assert_eq!(method, "GET");
1225            assert_eq!(path, "/\\?wayne\\=5");
1226            assert_eq!(version, 1);
1227            assert_eq!(headers.len(), 0);
1228            assert!(eof);
1229        }
1230    }
1231
1232    req_err! {
1233        test_request_with_invalid_token_delimiter,
1234        b"GET\n/ HTTP/1.1\r\nHost: foo.bar\r\n\r\n",
1235        Err(Error::Token)
1236    }
1237
1238    req_err! {
1239        test_request_with_invalid_but_short_version,
1240        b"GET / HTTP/1!",
1241        Err(Error::Version)
1242    }
1243
1244    req_err! {
1245        test_request_with_empty_method,
1246        b" / HTTP/1.1\r\n\r\n",
1247        Err(Error::Token)
1248    }
1249
1250    req_err! {
1251        test_request_with_empty_path,
1252        b"GET  HTTP/1.1\r\n\r\n",
1253        Err(Error::Token)
1254    }
1255
1256    req_err! {
1257        test_request_with_empty_method_and_path,
1258        b"  HTTP/1.1\r\n\r\n",
1259        Err(Error::Token)
1260    }
1261
1262    headers! {
1263        test_headers_optional_whitespace,
1264        b"Host: \tfoo.com\t \r\nCookie: \t \r\n",
1265        |len, headers, eof| {
1266            assert_eq!(len, 30);
1267            assert_eq!(headers.len(), 2);
1268            assert_eq!(headers[0].0, "Host");
1269            assert_eq!(headers[0].1, b"foo.com");
1270            assert_eq!(headers[1].0, "Cookie");
1271            assert_eq!(headers[1].1, b"");
1272            assert!(!eof);
1273        }
1274    }
1275
1276    #[test]
1277    fn test_headers_with_state() {
1278        const B1: &[u8] = b"Host";
1279        const B2: &[u8] = b"Host: \t";
1280        const B3: &[u8] = b"Host: \tfoo.com\t ";
1281        const B4: &[u8] = b"Host: \tfoo.com\t \r\nCoo";
1282        const B5: &[u8] = b"Host: \tfoo.com\t \r\nCookie: \t \r\n\r\n";
1283
1284        let mut st = State::default();
1285        let mut header = Header::default();
1286        assert!(header.parse_with_state(B1, &mut st).unwrap().is_partial());
1287        assert_eq!(st.state, 1);
1288        assert_eq!(st.start, 0);
1289        assert_eq!(st.cursor, 4);
1290        assert_eq!(header.name, SlicePos { start: 0, end: 0 });
1291        assert!(header.parse_with_state(B2, &mut st).unwrap().is_partial());
1292        assert_eq!(st.state, 2);
1293        assert_eq!(st.start, 0);
1294        assert_eq!(st.cursor, 7);
1295        assert_eq!(header.name, SlicePos { start: 0, end: 4 });
1296        assert_eq!(&B5[header.name.start..header.name.end], b"Host");
1297
1298        assert!(header.parse_with_state(B3, &mut st).unwrap().is_partial());
1299        assert_eq!(st.state, 3);
1300        assert_eq!(st.start, 0);
1301        assert_eq!(st.cursor, 16);
1302        assert_eq!(header.name, SlicePos { start: 0, end: 4 });
1303        assert_eq!(header.value, SlicePos { start: 7, end: 0 });
1304
1305        assert!(header.parse_with_state(B4, &mut st).unwrap().is_complete());
1306        assert_eq!(st.state, 0);
1307        assert_eq!(st.start, 18);
1308        assert_eq!(st.cursor, 18);
1309        assert_eq!(header.value, SlicePos { start: 7, end: 14 });
1310        assert_eq!(&B5[header.value.start..header.value.end], b"foo.com");
1311
1312        assert!(header.parse_with_state(B5, &mut st).unwrap().is_complete());
1313        assert_eq!(st.state, 0);
1314        assert_eq!(st.start, 30);
1315        assert_eq!(st.cursor, 30);
1316        assert_eq!(header.name, SlicePos { start: 18, end: 24 });
1317        assert_eq!(header.value, SlicePos { start: 0, end: 0 });
1318        assert_eq!(&B5[header.name.start..header.name.end], b"Cookie");
1319        assert_eq!(&B5[header.value.start..header.value.end], b"");
1320
1321        assert_eq!(
1322            header.parse_with_state(B5, &mut st),
1323            Ok(Status::Complete(HeaderParsed::Eof(32)))
1324        );
1325        assert_eq!(st.state, 0);
1326        assert_eq!(st.start, 32);
1327        assert_eq!(st.cursor, 32);
1328    }
1329
1330    headers_err! {
1331        test_headers_with_obsolete_line_folding_at_start,
1332        b"Line-Folded-Header: \r\n   \r\n hello there\r\n\r\n",
1333        Err(Error::HeaderName)
1334    }
1335
1336    headers_err! {
1337        test_header_with_invalid_name,
1338        b"Host : foo.bar\r\n\r\n",
1339        Err(Error::HeaderName)
1340    }
1341
1342    macro_rules! res {
1343        ($name:ident, $buf:expr, |$len:ident, $version:ident, $code:ident, $reason:ident, $headers:ident, $headers_eof:ident| $body:expr) => {
1344            #[test]
1345            fn $name() {
1346                let mut b = $buf.as_ref();
1347                let mut res = Response::default();
1348                let mut consumed = res.parse($buf.as_ref()).unwrap().unwrap();
1349                let mut headers = Vec::new();
1350                let mut header = Header::default();
1351                let mut headers_eof = false;
1352                b = &b[consumed..];
1353
1354                while let Status::Complete(hdr) = header.parse(b).unwrap() {
1355                    match hdr {
1356                        HeaderParsed::Header(l) => {
1357                            consumed += l;
1358                            let name = String::from_utf8(Vec::from(
1359                                &b[header.name.start..header.name.end],
1360                            ))
1361                            .unwrap();
1362                            let value = Vec::from(&b[header.value.start..header.value.end]);
1363                            headers.push((name, value));
1364                            b = &b[l..];
1365                        }
1366                        HeaderParsed::Eof(l) => {
1367                            consumed += l;
1368                            headers_eof = true;
1369                            break;
1370                        }
1371                    }
1372                }
1373
1374                // SAFETY: Request::parse() validates reason
1375                let reason = unsafe {
1376                    str::from_utf8_unchecked(&$buf.as_ref()[res.reason.start..res.reason.end])
1377                };
1378
1379                closure(
1380                    consumed,
1381                    res.version,
1382                    res.code,
1383                    reason,
1384                    headers,
1385                    headers_eof,
1386                );
1387
1388                fn closure(
1389                    $len: usize,
1390                    $version: u8,
1391                    $code: u16,
1392                    $reason: &str,
1393                    $headers: Vec<(String, Vec<u8>)>,
1394                    $headers_eof: bool,
1395                ) {
1396                    $body
1397                }
1398            }
1399        };
1400    }
1401
1402    macro_rules! res_err {
1403        ($name:ident, $buf:expr, $err:expr) => {
1404            #[test]
1405            fn $name() {
1406                assert_eq!(Response::default().parse($buf.as_ref()), $err);
1407            }
1408        };
1409    }
1410
1411    macro_rules! res_par {
1412        ($name:ident, $buf:expr) => {
1413            #[test]
1414            fn $name() {
1415                assert_eq!(
1416                    Response::default().parse($buf.as_ref()),
1417                    Ok(Status::Partial)
1418                );
1419            }
1420        };
1421    }
1422
1423    res_err! {
1424        test_response_newline_after_version,
1425        b"HTTP/1.1\r\n\r\n 200 OK\r\n\r\n",
1426        Err(Error::Version)
1427    }
1428
1429    res_err! {
1430        test_response_bare_newline_after_version,
1431        b"HTTP/1.1\n 200 OK\r\n\r\n",
1432        Err(Error::Version)
1433    }
1434
1435    res! {
1436        test_response_simple,
1437        b"HTTP/1.1 200 OK\r\n\r\n",
1438        |len, version, code, reason, headers, eof| {
1439            assert_eq!(len, 19);
1440            assert_eq!(version, 1);
1441            assert_eq!(code, 200);
1442            assert_eq!(reason, "OK");
1443            assert_eq!(headers.len(), 0);
1444            assert!(eof);
1445        }
1446    }
1447
1448    res! {
1449        test_response_newlines,
1450        b"HTTP/1.0 403 Forbidden\nServer: foo.bar\n\n",
1451        |len, version, code, reason, headers, eof| {
1452            assert_eq!(len, 40);
1453            assert_eq!(version, 0);
1454            assert_eq!(code, 403);
1455            assert_eq!(reason, "Forbidden");
1456            assert_eq!(headers.len(), 1);
1457            assert_eq!(headers[0].0, "Server");
1458            assert_eq!(headers[0].1, b"foo.bar");
1459            assert!(eof);
1460        }
1461    }
1462
1463    res! {
1464        test_response_reason_missing,
1465        b"HTTP/1.1 200 \r\n\r\n",
1466        |len, version, code, reason, headers, eof| {
1467            assert_eq!(len, 17);
1468            assert_eq!(version, 1);
1469            assert_eq!(code, 200);
1470            assert_eq!(reason, "");
1471            assert_eq!(headers.len(), 0);
1472            assert!(eof);
1473        }
1474    }
1475
1476    res! {
1477        test_response_reason_missing_no_space,
1478        b"HTTP/1.1 200\r\n\r\n",
1479        |len, version, code, reason, headers, eof| {
1480            assert_eq!(len, 16);
1481            assert_eq!(version, 1);
1482            assert_eq!(code, 200);
1483            assert_eq!(reason, "");
1484            assert_eq!(headers.len(), 0);
1485            assert!(eof);
1486        }
1487    }
1488
1489    res! {
1490        test_response_reason_missing_no_space_with_headers,
1491        b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n",
1492        |len, version, code, reason, headers, eof| {
1493            assert_eq!(len, 26);
1494            assert_eq!(version, 1);
1495            assert_eq!(code, 200);
1496            assert_eq!(reason, "");
1497            assert_eq!(headers.len(), 1);
1498            assert_eq!(headers[0].0, "Foo");
1499            assert_eq!(headers[0].1, b"bar");
1500            assert!(eof);
1501        }
1502    }
1503
1504    res! {
1505        test_response_reason_with_space_and_tab,
1506        b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n",
1507        |len, version, code, reason, headers, eof| {
1508            assert_eq!(len, 37);
1509            assert_eq!(version, 1);
1510            assert_eq!(code, 101);
1511            assert_eq!(reason, "Switching Protocols\t");
1512            assert_eq!(headers.len(), 0);
1513            assert!(eof);
1514        }
1515    }
1516
1517    res! {
1518        test_response_reason_with_obsolete_text_byte,
1519        b"HTTP/1.1 200 X\xFFZ\r\n\r\n",
1520        |len, version, code, reason, headers, eof| {
1521            assert_eq!(len, 20);
1522            assert_eq!(version, 1);
1523            assert_eq!(code, 200);
1524            // Empty string fallback in case of obs-text
1525            assert_eq!(reason, "");
1526            assert_eq!(headers.len(), 0);
1527            assert!(eof);
1528        }
1529    }
1530
1531    res_err! {
1532        test_response_reason_with_nul_byte,
1533        b"HTTP/1.1 200 \x00\r\n\r\n",
1534        Err(crate::Error::Status)
1535    }
1536
1537    #[test]
1538    fn test_response_reason_bytes_at_every_position() {
1539        const PREFIX: &[u8] = b"HTTP/1.1 200 ";
1540        // miri is too slow for the full matrix, check the block boundaries
1541        let lens: Vec<usize> = if cfg!(miri) {
1542            vec![1, 8, 9, 17, 33]
1543        } else {
1544            (1..80).collect()
1545        };
1546        for len in lens {
1547            for pos in 0..len {
1548                for b in [b'\t', b' ', b'~', 0x00, 0x0b, 0x7f, 0x80, 0xff] {
1549                    let mut reason = vec![b'a'; len];
1550                    reason[pos] = b;
1551                    let buf = [PREFIX, &reason, b"\r\n"].concat();
1552                    let valid = b == b'\t' || b == b' ' || b == b'~' || b >= 0x80;
1553
1554                    // parse at once and resumed at every split point
1555                    let splits: Vec<usize> = if cfg!(miri) {
1556                        let at = PREFIX.len() + pos;
1557                        vec![PREFIX.len(), at, at + 1, buf.len()]
1558                    } else {
1559                        (PREFIX.len()..=buf.len()).collect()
1560                    };
1561                    for split in splits {
1562                        let mut resp = Response::default();
1563                        let mut st = State::default();
1564                        let first = resp.parse_with_state(&buf[..split], &mut st);
1565                        let res = if split == buf.len() {
1566                            first
1567                        } else if first.is_err() {
1568                            assert!(!valid, "len {len} pos {pos} byte {b:#x} split {split}");
1569                            continue;
1570                        } else {
1571                            assert_eq!(first, Ok(Status::Partial));
1572                            resp.parse_with_state(&buf, &mut st)
1573                        };
1574                        let ctx = format!("len {len} pos {pos} byte {b:#x} split {split}");
1575                        if !valid {
1576                            assert_eq!(res, Err(crate::Error::Status), "{ctx}");
1577                        } else if b >= 0x80 {
1578                            assert_eq!(res, Ok(Status::Complete(buf.len())), "{ctx}");
1579                            assert_eq!(resp.reason, SlicePos::default(), "{ctx}");
1580                        } else {
1581                            assert_eq!(res, Ok(Status::Complete(buf.len())), "{ctx}");
1582                            // leading spaces are skipped, trailing whitespace is kept
1583                            let start = usize::from(pos == 0 && b == b' ');
1584                            assert_eq!(
1585                                &buf[resp.reason.start..resp.reason.end],
1586                                &reason[start..],
1587                                "{ctx}"
1588                            );
1589                        }
1590                    }
1591                }
1592            }
1593        }
1594    }
1595
1596    #[test]
1597    fn test_response_reason_ascii_block_boundaries() {
1598        const PREFIX: &[u8] = b"HTTP/1.1 200 ";
1599        for len in [
1600            63, 64, 65, 71, 72, 73, 127, 128, 129, 135, 136, 137, 199, 200, 255, 256,
1601        ] {
1602            for pos in [
1603                None,
1604                Some(0),
1605                Some(7),
1606                Some(8),
1607                Some(63),
1608                Some(64),
1609                Some(len - 1),
1610            ] {
1611                if pos.is_some_and(|pos| pos >= len) {
1612                    continue;
1613                }
1614                let mut reason = vec![b'a'; len];
1615                if let Some(pos) = pos {
1616                    reason[pos] = 0xff;
1617                }
1618                let mut buf = [PREFIX, &reason, b"\r\n"].concat();
1619                let consumed = buf.len();
1620                let expected = if pos.is_some() {
1621                    SlicePos::default()
1622                } else {
1623                    SlicePos {
1624                        start: PREFIX.len(),
1625                        end: PREFIX.len() + len,
1626                    }
1627                };
1628                let mut resp = Response::default();
1629                assert_eq!(resp.parse(&buf), Ok(Status::Complete(consumed)));
1630                assert_eq!(resp.reason, expected, "len {len} pos {pos:?}");
1631                check_split(&buf, Response::parse_with_state, Response::parse);
1632
1633                buf.extend_from_slice(b"X-Next: \xff\r\n\r\n");
1634                let mut resp = Response::default();
1635                assert_eq!(resp.parse(&buf), Ok(Status::Complete(consumed)));
1636                assert_eq!(resp.reason, expected, "len {len} pos {pos:?}");
1637            }
1638        }
1639    }
1640
1641    res_par! {
1642        test_response_version_missing_space,
1643        b"HTTP/1.1"
1644    }
1645
1646    res_par! {
1647         test_response_code_missing_space,
1648         b"HTTP/1.1 200"
1649    }
1650
1651    res! {
1652        test_response_partial_parses_headers_as_much_as_it_can,
1653        b"HTTP/1.1 200 OK\r\nServer: yolo\r\n",
1654        |len, version, code, reason, headers, eof| {
1655            assert_eq!(len, 31);
1656            assert_eq!(version, 1);
1657            assert_eq!(code, 200);
1658            assert_eq!(reason, "OK");
1659            assert_eq!(headers.len(), 1);
1660            assert_eq!(headers[0].0, "Server");
1661            assert_eq!(headers[0].1, b"yolo");
1662            assert!(!eof);
1663        }
1664    }
1665
1666    res! {
1667        test_response_empty_lines_prefix_lf_only,
1668        b"\n\nHTTP/1.1 200 OK\n\n",
1669        |len, version, code, reason, headers, eof| {
1670            assert_eq!(len, 19);
1671            assert_eq!(version, 1);
1672            assert_eq!(code, 200);
1673            assert_eq!(reason, "OK");
1674            assert_eq!(headers.len(), 0);
1675            assert!(eof);
1676        }
1677    }
1678
1679    res! {
1680        test_response_no_cr,
1681        b"HTTP/1.0 200\nContent-type: text/html\n\n",
1682        |len, version, code, reason, headers, eof| {
1683            assert_eq!(len, 38);
1684            assert_eq!(version, 0);
1685            assert_eq!(code, 200);
1686            assert_eq!(reason, "");
1687            assert_eq!(headers.len(), 1);
1688            assert_eq!(headers[0].0, "Content-type");
1689            assert_eq!(headers[0].1, b"text/html");
1690            assert!(eof);
1691        }
1692    }
1693
1694    /// Check all subset permutations of a partial request line with no headers
1695    #[test]
1696    fn partial_permutations() {
1697        let req_str = "GET / HTTP/1.1\r\n";
1698        let mut req = Request::default();
1699        for i in 0..req_str.len() {
1700            let status = req.parse(&req_str.as_bytes()[..i]);
1701            assert_eq!(
1702                status,
1703                Ok(Status::Partial),
1704                "partial request line should return partial. \
1705                  Portion which failed: '{seg}' (below {i})",
1706                seg = &req_str[..i]
1707            );
1708        }
1709    }
1710
1711    headers_err! {
1712        test_forbid_headers_with_whitespace_between_header_name_and_colon,
1713        b"Access-Control-Allow-Credentials : true\r\nBread: baguette\r\n\r\n",
1714        Err(Error::HeaderName)
1715    }
1716
1717    headers_err! {
1718        test_forbid_headers_with_obsolete_line_folding_at_end,
1719        b"Line-Folded-Header: hello there\r\n   \r\n \r\n\r\n",
1720        Err(Error::HeaderName)
1721    }
1722
1723    headers_err! {
1724        test_forbid_headers_with_obsolete_line_folding_in_middle,
1725        b"Line-Folded-Header: hello  \r\n \r\n there\r\n\r\n",
1726        Err(Error::HeaderName)
1727    }
1728
1729    headers_err! {
1730        test_forbid_headers_with_obsolete_line_folding_in_empty_header,
1731        b"Line-Folded-Header:   \r\n \r\n \r\n\r\n",
1732        Err(Error::HeaderName)
1733    }
1734
1735    headers_err! {
1736        test_forbid_headers_with_empty_header_name,
1737        b": hello\r\nBread: baguette\r\n\r\n",
1738        Err(Error::HeaderName)
1739    }
1740
1741    headers_err! {
1742        test_forbid_headers_with_empty_header_name_second,
1743        b"Bread: baguette\r\n: hello\r\n\r\n",
1744        Err(Error::HeaderName)
1745    }
1746
1747    #[test]
1748    fn test_chunk_size() {
1749        assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
1750        assert_eq!(
1751            parse_chunk_size(b"12\r\nchunk"),
1752            Ok(Status::Complete((4, 18)))
1753        );
1754        assert_eq!(
1755            parse_chunk_size(b"3086d\r\n"),
1756            Ok(Status::Complete((7, 198_765)))
1757        );
1758        assert_eq!(
1759            parse_chunk_size(b"3735AB1;foo bar*\r\n"),
1760            Ok(Status::Complete((18, 57_891_505)))
1761        );
1762        assert_eq!(
1763            parse_chunk_size(b"3735ab1 ; baz \r\n"),
1764            Ok(Status::Complete((16, 57_891_505)))
1765        );
1766        assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial));
1767        assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial));
1768        assert_eq!(
1769            parse_chunk_size(b"567f8a\rfoo"),
1770            Err(crate::InvalidChunkSize)
1771        );
1772        assert_eq!(
1773            parse_chunk_size(b"567f8a\rfoo"),
1774            Err(crate::InvalidChunkSize)
1775        );
1776        assert_eq!(
1777            parse_chunk_size(b"567xf8a\r\n"),
1778            Err(crate::InvalidChunkSize)
1779        );
1780        assert_eq!(
1781            parse_chunk_size(b"ffffffffffffffff\r\n"),
1782            Ok(Status::Complete((18, u64::MAX)))
1783        );
1784        assert_eq!(
1785            parse_chunk_size(b"1ffffffffffffffff\r\n"),
1786            Err(crate::InvalidChunkSize)
1787        );
1788        assert_eq!(
1789            parse_chunk_size(b"Affffffffffffffff\r\n"),
1790            Err(crate::InvalidChunkSize)
1791        );
1792        assert_eq!(
1793            parse_chunk_size(b"fffffffffffffffff\r\n"),
1794            Err(crate::InvalidChunkSize)
1795        );
1796    }
1797
1798    #[test]
1799    fn test_chunk_size_empty() {
1800        for buf in [&b"\r\n"[..], b";a\r\n", b" \r\n", b"\t;a\r\n", b"\r"] {
1801            assert_eq!(
1802                parse_chunk_size(buf),
1803                Err(crate::InvalidChunkSize),
1804                "{buf:?}"
1805            );
1806        }
1807        assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
1808    }
1809
1810    // Feeds every prefix of `buf` to the resumable parser and checks that the
1811    // result matches parsing the whole buffer at once.
1812    fn header_split(buf: &[u8]) -> (Result<HeaderParsed>, Header) {
1813        let mut one = Header::default();
1814        let expected = one.parse(buf);
1815        for split in 0..buf.len() {
1816            let mut h = Header::default();
1817            let mut st = State::default();
1818            let first = h.parse_with_state(&buf[..split], &mut st);
1819            if first.is_err() {
1820                assert_eq!(first, expected, "split {split} of {buf:?}");
1821                continue;
1822            }
1823            assert_eq!(first, Ok(Status::Partial), "split {split} of {buf:?}");
1824            let res = h.parse_with_state(buf, &mut st);
1825            assert_eq!(res, expected, "split {split} of {buf:?}");
1826            if expected.is_ok() {
1827                assert_eq!(h, one, "split {split} of {buf:?}");
1828            }
1829        }
1830        (expected, one)
1831    }
1832
1833    #[test]
1834    fn test_header_split_bare_cr() {
1835        assert_eq!(header_split(b"X: a\rb\r\n").0, Err(Error::HeaderValue));
1836        assert_eq!(header_split(b"X:\rb\r\n").0, Err(Error::HeaderValue));
1837        assert_eq!(header_split(b"\rX: b\r\n").0, Err(Error::NewLine));
1838
1839        let (res, h) = header_split(b"X: a b\r\n");
1840        assert_eq!(res, Ok(Status::Complete(HeaderParsed::Header(8))));
1841        assert_eq!(h.value, SlicePos { start: 3, end: 6 });
1842        assert_eq!(
1843            header_split(b"X:\r\n").0,
1844            Ok(Status::Complete(HeaderParsed::Header(4)))
1845        );
1846        assert_eq!(
1847            header_split(b"\r\n").0,
1848            Ok(Status::Complete(HeaderParsed::Eof(2)))
1849        );
1850    }
1851
1852    #[test]
1853    fn test_request_split() {
1854        for buf in [
1855            &b"GET /path HTTP/1.1\r\n"[..],
1856            b"GET  /path   HTTP/1.1\r\n",
1857            b"PUT /path HTTP/1.0\n",
1858            b"CUSTOM  /path HTTP/1.1\r\n",
1859            b"\r\n\nPOST /path HTTP/1.1\r\n",
1860            b"GET /path HTTP/1.1\r\r\n",
1861            b"GET /path HTTP/1.1\rX",
1862            b"\rGET /path HTTP/1.1\r\n",
1863            b"GE\x00T /path HTTP/1.1\r\n",
1864            b"GET /pa\x7fth HTTP/1.1\r\n",
1865            b"GET /path HTTP/2.0\r\n",
1866        ] {
1867            check_split(buf, Request::parse_with_state, Request::parse);
1868        }
1869    }
1870
1871    #[test]
1872    fn test_response_split() {
1873        for buf in [
1874            &b"HTTP/1.1 200 OK\r\n"[..],
1875            b"HTTP/1.0 404  Not Found \n",
1876            b"\r\nHTTP/1.1 200\r\n",
1877            b"HTTP/1.1 200\n",
1878            b"HTTP/1.1   200 \r\n",
1879            b"HTTP/1.1 200 caf\xc3\xa9\r\n",
1880            b"HTTP/1.1 200 OK\r\r\n",
1881            b"HTTP/1.1 200\rX",
1882            b"HTTP/1.1 2x0 OK\r\n",
1883            b"HTTP/1.1\r\n200 OK\r\n",
1884            b"HTTP/1.1 200 O\x00K\r\n",
1885        ] {
1886            check_split(buf, Response::parse_with_state, Response::parse);
1887        }
1888    }
1889
1890    #[test]
1891    fn test_response_empty_reason() {
1892        for buf in [
1893            &b"HTTP/1.1 200\r\n"[..],
1894            b"HTTP/1.1 200 \r\n",
1895            b"HTTP/1.1 200   \r\n",
1896            b"HTTP/1.1 200\n",
1897            b"HTTP/1.1 200 \n",
1898            b"\r\nHTTP/1.1 200   \n",
1899        ] {
1900            let mut resp = Response::default();
1901            assert_eq!(resp.parse(buf), Ok(Status::Complete(buf.len())));
1902            assert_eq!(resp.reason, SlicePos::default());
1903            check_split(buf, Response::parse_with_state, Response::parse);
1904        }
1905    }
1906
1907    // Feeds `buf` split at every position, and byte by byte, to the resumable
1908    // parser and checks that the result matches parsing it at once.
1909    fn check_split<T: Default + PartialEq + fmt::Debug>(
1910        buf: &[u8],
1911        parse: fn(&mut T, &[u8], &mut State) -> Result<usize>,
1912        one_shot: fn(&mut T, &[u8]) -> Result<usize>,
1913    ) {
1914        let mut one = T::default();
1915        let expected = one_shot(&mut one, buf);
1916        let check = |res: Result<usize>, v: &T, what: &str| {
1917            assert_eq!(res, expected, "{what} of {buf:?}");
1918            if expected.is_ok() {
1919                assert_eq!(v, &one, "{what} of {buf:?}");
1920            }
1921        };
1922
1923        for split in 0..buf.len() {
1924            let mut v = T::default();
1925            let mut st = State::default();
1926            let first = parse(&mut v, &buf[..split], &mut st);
1927            if first.is_err() {
1928                check(first, &v, &format!("split {split}"));
1929                continue;
1930            }
1931            assert_eq!(first, Ok(Status::Partial), "split {split} of {buf:?}");
1932            let res = parse(&mut v, buf, &mut st);
1933            check(res, &v, &format!("split {split}"));
1934        }
1935
1936        let mut v = T::default();
1937        let mut st = State::default();
1938        for len in 0..=buf.len() {
1939            let res = parse(&mut v, &buf[..len], &mut st);
1940            if res != Ok(Status::Partial) || len == buf.len() {
1941                check(res, &v, &format!("byte by byte, len {len}"));
1942                break;
1943            }
1944            // accepted input is not scanned again, except the version and the
1945            // status code, at most 9 bytes
1946            assert!(st.cursor + 9 >= len, "len {len} of {buf:?}");
1947        }
1948    }
1949
1950    #[test]
1951    fn test_request_resumes_long_method() {
1952        let buf = [b'A'; 4096];
1953        let mut req = Request::default();
1954        let mut st = State::default();
1955        assert_eq!(req.parse_with_state(&buf, &mut st), Ok(Status::Partial));
1956        assert_eq!((st.state, st.start, st.cursor), (1, 0, 4096));
1957    }
1958
1959    #[test]
1960    fn test_header_name_chars_at_every_position() {
1961        // covers the scalar prefix, the SIMD blocks and the tail
1962        let (lens, bytes): (&[usize], Vec<u8>) = if cfg!(miri) {
1963            // miri is too slow for the full matrix
1964            let bytes = [
1965                0x00, b'\t', b' ', b'!', b'"', b'x', b':', b'~', 0x7f, 0x80, 0xff,
1966            ];
1967            (&[1, 16, 17, 33], bytes.to_vec())
1968        } else {
1969            (
1970                &[1, 15, 16, 17, 31, 32, 33, 47, 48, 70],
1971                (0..=255).collect(),
1972            )
1973        };
1974        for &len in lens {
1975            for pos in 1..len {
1976                for &b in &bytes {
1977                    let mut buf = vec![b'x'; len];
1978                    buf[pos] = b;
1979                    buf.extend_from_slice(b": v\r\n");
1980                    let res = Header::default().parse(&buf);
1981                    if utils::TOKEN_MAP[b as usize] {
1982                        assert_eq!(
1983                            res,
1984                            Ok(Status::Complete(HeaderParsed::Header(len + 5))),
1985                            "len {len} pos {pos} byte {b}"
1986                        );
1987                    } else if b == b':' {
1988                        assert!(res.is_ok(), "len {len} pos {pos}");
1989                    } else {
1990                        assert_eq!(res, Err(Error::HeaderName), "len {len} pos {pos} byte {b}");
1991                    }
1992                }
1993            }
1994        }
1995    }
1996
1997    #[test]
1998    fn test_header_state_reuse() {
1999        let buf = b"A: 1\r\nB: 2\r\n\r\nbody";
2000        let mut h = Header::default();
2001        let mut st = State::default();
2002        assert_eq!(
2003            h.parse_with_state(buf, &mut st),
2004            Ok(Status::Complete(HeaderParsed::Header(6)))
2005        );
2006        assert_eq!(
2007            h.parse_with_state(buf, &mut st),
2008            Ok(Status::Complete(HeaderParsed::Header(12)))
2009        );
2010        assert_eq!((h.name.start, h.value.end), (6, 10));
2011        assert_eq!(
2012            h.parse_with_state(buf, &mut st),
2013            Ok(Status::Complete(HeaderParsed::Eof(14)))
2014        );
2015    }
2016
2017    #[test]
2018    fn test_invalid_state() {
2019        for st in [
2020            State {
2021                state: 3,
2022                start: 0,
2023                cursor: 100,
2024            },
2025            State {
2026                state: 1,
2027                start: 2,
2028                cursor: 1,
2029            },
2030            State {
2031                state: 8,
2032                start: 0,
2033                cursor: 0,
2034            },
2035        ] {
2036            let mut s = st;
2037            assert_eq!(
2038                Header::default().parse_with_state(b"abc", &mut s),
2039                Err(Error::HeaderName)
2040            );
2041            let mut s = st;
2042            assert_eq!(
2043                Request::default().parse_with_state(b"abc", &mut s),
2044                Err(Error::Token)
2045            );
2046            let mut s = st;
2047            assert_eq!(
2048                Response::default().parse_with_state(b"abc", &mut s),
2049                Err(Error::Status)
2050            );
2051        }
2052    }
2053
2054    #[test]
2055    fn test_chunk_size_extension_control_chars() {
2056        for buf in [
2057            &b"4;a\nX\r\n"[..],
2058            b"4;a=\"\nX\"\r\n",
2059            b"4;a\x00\r\n",
2060            b"4;a\x7f\r\n",
2061            b"4;\n",
2062        ] {
2063            assert_eq!(
2064                parse_chunk_size(buf),
2065                Err(crate::InvalidChunkSize),
2066                "{buf:?}"
2067            );
2068        }
2069        assert_eq!(
2070            parse_chunk_size(b"4 ;a=\"b\tc \x80\";d\t\r\n"),
2071            Ok(Status::Complete((17, 4)))
2072        );
2073    }
2074
2075    res! {
2076        test_allow_response_with_multiple_space_delimiters,
2077        b"HTTP/1.1   200  OK\r\n\r\n",
2078        |len, version, code, reason, headers, eof| {
2079            assert_eq!(len, 22);
2080            assert_eq!(version, 1);
2081            assert_eq!(code, 200);
2082            assert_eq!(reason, "OK");
2083            assert_eq!(headers.len(), 0);
2084            assert!(eof);
2085        }
2086    }
2087
2088    // /// This is technically allowed by the spec, but we only support multiple spaces as an option,
2089    // /// not stray `\r`s.
2090    res_err! {
2091        test_forbid_response_with_weird_whitespace_delimiters,
2092        b"HTTP/1.1 200\rOK\r\n\r\n",
2093        Err(Error::Status)
2094    }
2095
2096    req! {
2097        test_allow_request_with_multiple_space_delimiters,
2098        b"GET  /    HTTP/1.1\r\n\r\n",
2099        |len, method, path, version, headers, eof| {
2100            assert_eq!(len, 22);
2101            assert_eq!(method, "GET");
2102            assert_eq!(path, "/");
2103            assert_eq!(version, 1);
2104            assert_eq!(headers.len(), 0);
2105            assert!(eof);
2106        }
2107    }
2108
2109    // /// This is technically allowed by the spec, but we only support multiple spaces as an option,
2110    // /// not stray `\r`s.
2111    req_err! {
2112        test_forbid_request_with_weird_whitespace_delimiters,
2113        b"GET\r/\rHTTP/1.1\r\n\r\n",
2114        Err(Error::Token)
2115    }
2116
2117    req_err! {
2118        test_request_with_multiple_spaces_and_bad_path,
2119        b"GET   /foo ohno HTTP/1.1\r\n\r\n",
2120        Err(Error::Version)
2121    }
2122
2123    // // This test ensure there is an error when there is a DEL character in the path
2124    // // since we allow all char from 0x21 code except DEL, this test ensure that DEL
2125    // // is not allowed in the path
2126    req_err! {
2127        test_request_with_del_in_path,
2128        b"GET   /foo\x7Fohno HTTP/1.1\r\n\r\n",
2129        Err(Error::Token)
2130    }
2131
2132    // #[test]
2133    // #[cfg_attr(miri, ignore)] // Miri is too slow for this test
2134    // fn test_all_utf8_char_in_paths() {
2135    //     // two code points
2136    //     for i in 128..256 {
2137    //         for j in 128..256 {
2138    //             let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2139    //             let mut request = Request::new(&mut headers[..]);
2140    //             let bytes = [i as u8, j as u8];
2141
2142    //             match core::str::from_utf8(&bytes) {
2143    //                 Ok(s) => {
2144    //                     let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
2145    //                     let result = crate::ParserConfig::default()
2146    //                         .allow_multiple_spaces_in_request_line_delimiters(true)
2147    //                         .parse_request(&mut request, first_line.as_bytes());
2148
2149    //                     assert_eq!(
2150    //                         result,
2151    //                         Ok(Status::Complete(20)),
2152    //                         "failed for utf8 char i: {}, j: {}",
2153    //                         i,
2154    //                         j
2155    //                     );
2156    //                 }
2157    //                 Err(_) => {
2158    //                     let mut first_line = b"GET /".to_vec();
2159    //                     first_line.extend(&bytes);
2160    //                     first_line.extend(b" HTTP/1.1\r\n\r\n");
2161
2162    //                     let result = crate::ParserConfig::default()
2163    //                         .allow_multiple_spaces_in_request_line_delimiters(true)
2164    //                         .parse_request(&mut request, first_line.as_slice());
2165
2166    //                     assert_eq!(
2167    //                         result,
2168    //                         Err(crate::Error::Token),
2169    //                         "failed for utf8 char i: {}, j: {}",
2170    //                         i,
2171    //                         j
2172    //                     );
2173    //                 }
2174    //             };
2175
2176    //             // three code points starting from 0xe0
2177    //             if i < 0xe0 {
2178    //                 continue;
2179    //             }
2180
2181    //             for k in 128..256 {
2182    //                 let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2183    //                 let mut request = Request::new(&mut headers[..]);
2184    //                 let bytes = [i as u8, j as u8, k as u8];
2185
2186    //                 match core::str::from_utf8(&bytes) {
2187    //                     Ok(s) => {
2188    //                         let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
2189    //                         let result = crate::ParserConfig::default()
2190    //                             .allow_multiple_spaces_in_request_line_delimiters(true)
2191    //                             .parse_request(&mut request, first_line.as_bytes());
2192
2193    //                         assert_eq!(
2194    //                             result,
2195    //                             Ok(Status::Complete(21)),
2196    //                             "failed for utf8 char i: {}, j: {}, k: {}",
2197    //                             i,
2198    //                             j,
2199    //                             k
2200    //                         );
2201    //                     }
2202    //                     Err(_) => {
2203    //                         let mut first_line = b"GET /".to_vec();
2204    //                         first_line.extend(&bytes);
2205    //                         first_line.extend(b" HTTP/1.1\r\n\r\n");
2206
2207    //                         let result = crate::ParserConfig::default()
2208    //                             .allow_multiple_spaces_in_request_line_delimiters(true)
2209    //                             .parse_request(&mut request, first_line.as_slice());
2210
2211    //                         assert_eq!(
2212    //                             result,
2213    //                             Err(crate::Error::Token),
2214    //                             "failed for utf8 char i: {}, j: {}, k: {}",
2215    //                             i,
2216    //                             j,
2217    //                             k
2218    //                         );
2219    //                     }
2220    //                 };
2221
2222    //                 // four code points starting from 0xf0
2223    //                 if i < 0xf0 {
2224    //                     continue;
2225    //                 }
2226
2227    //                 for l in 128..256 {
2228    //                     let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2229    //                     let mut request = Request::new(&mut headers[..]);
2230    //                     let bytes = [i as u8, j as u8, k as u8, l as u8];
2231
2232    //                     match core::str::from_utf8(&bytes) {
2233    //                         Ok(s) => {
2234    //                             let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
2235    //                             let result = crate::ParserConfig::default()
2236    //                                 .allow_multiple_spaces_in_request_line_delimiters(true)
2237    //                                 .parse_request(&mut request, first_line.as_bytes());
2238
2239    //                             assert_eq!(
2240    //                                 result,
2241    //                                 Ok(Status::Complete(22)),
2242    //                                 "failed for utf8 char i: {}, j: {}, k: {}, l: {}",
2243    //                                 i,
2244    //                                 j,
2245    //                                 k,
2246    //                                 l
2247    //                             );
2248    //                         }
2249    //                         Err(_) => {
2250    //                             let mut first_line = b"GET /".to_vec();
2251    //                             first_line.extend(&bytes);
2252    //                             first_line.extend(b" HTTP/1.1\r\n\r\n");
2253
2254    //                             let result = crate::ParserConfig::default()
2255    //                                 .allow_multiple_spaces_in_request_line_delimiters(true)
2256    //                                 .parse_request(&mut request, first_line.as_slice());
2257
2258    //                             assert_eq!(
2259    //                                 result,
2260    //                                 Err(crate::Error::Token),
2261    //                                 "failed for utf8 char i: {}, j: {}, k: {}, l: {}",
2262    //                                 i,
2263    //                                 j,
2264    //                                 k,
2265    //                                 l
2266    //                             );
2267    //                         }
2268    //                     };
2269    //                 }
2270    //             }
2271    //         }
2272    //     }
2273    // }
2274
2275    res_err! {
2276        test_response_with_spaces_in_code,
2277        b"HTTP/1.1 99 200 OK\r\n\r\n",
2278        Err(Error::Status)
2279    }
2280
2281    headers_err! {
2282        test_headers_with_whitespace_between_header_name_and_colon,
2283        b"Access-Control-Allow-Credentials  : true\r\nBread: baguette\r\n\r\n",
2284        Err(Error::HeaderName)
2285    }
2286
2287    headers_err! {
2288        test_headers_with_invalid_char_between_header_name_and_colon,
2289        b"Access-Control-Allow-Credentials\xFF: true\r\nBread: baguette\r\n\r\n",
2290        Err(Error::HeaderName)
2291    }
2292
2293    headers_err! {
2294        test_ignore_header_line_with_missing_colon_in_response,
2295        b"Access-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n",
2296        Err(Error::HeaderName)
2297    }
2298
2299    headers_err! {
2300        test_headers_header_with_missing_colon_with_folding,
2301        b"Access-Control-Allow-Credentials   \r\n hello\r\nBread: baguette\r\n\r\n",
2302        Err(Error::HeaderName)
2303    }
2304
2305    headers_err! {
2306        test_headers_header_with_nul_in_header_name,
2307        b"Access-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n",
2308        Err(Error::HeaderName)
2309    }
2310
2311    headers_err! {
2312        test_header_with_cr_in_header_name,
2313        b"Access-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n",
2314        Err(Error::HeaderName)
2315    }
2316
2317    headers_err! {
2318        test_header_with_nul_in_whitespace_before_colon,
2319        b"Access-Control-Allow-Credentials   \0: hello\r\nBread: baguette\r\n\r\n",
2320        Err(Error::HeaderName)
2321    }
2322
2323    headers_err! {
2324        test_header_with_nul_in_value,
2325        b"Access-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n",
2326        Err(Error::HeaderValue)
2327    }
2328
2329    headers_err! {
2330        test_header_with_invalid_char_in_value,
2331        b"Access-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n",
2332        Err(Error::HeaderValue)
2333    }
2334
2335    headers_err! {
2336        test_header_with_invalid_char_in_value_with_folding,
2337        b"Access-Control-Allow-Credentials: hell\x01o  \n world!\r\nBread: baguette\r\n\r\n",
2338        Err(Error::HeaderValue)
2339    }
2340
2341    headers_err! {
2342        test_header_with_space_before_first_header,
2343        b" Space-Before-Header: hello there\r\n\r\n",
2344        Err(Error::HeaderName)
2345    }
2346
2347    res! {
2348        test_response_no_space_after_colon,
2349        b"HTTP/1.1 200 OK\r\nfoo:bar\r\n\r\n",
2350        |len, version, code, reason, headers, eof| {
2351            assert_eq!(len, 28);
2352            assert_eq!(version, 1);
2353            assert_eq!(code, 200);
2354            assert_eq!(reason, "OK");
2355            assert_eq!(headers.len(), 1);
2356            assert_eq!(headers[0].0, "foo");
2357            assert_eq!(headers[0].1, b"bar");
2358            assert!(eof);
2359        }
2360    }
2361
2362    req_err! {
2363        test_request_with_leading_space,
2364        b" GET / HTTP/1.1\r\nfoo:bar\r\n\r\n",
2365        Err(Error::Token)
2366    }
2367
2368    req_err! {
2369        test_request_with_invalid_method,
2370        b"P()ST / HTTP/1.1\r\nfoo:bar\r\n\r\n",
2371        Err(Error::Token)
2372    }
2373
2374    req! {
2375        test_utf8_in_path_ok,
2376        b"GET /test?post=I\xE2\x80\x99msorryIforkedyou HTTP/1.1\r\nHost: example.org\r\n\r\n",
2377        |len, method, path, version, headers, eof| {
2378            assert_eq!(len, 67);
2379            assert_eq!(method, "GET");
2380            assert_eq!(path, "/test?post=I’msorryIforkedyou");
2381            assert_eq!(version, 1);
2382            assert_eq!(headers.len(), 1);
2383            assert_eq!(headers[0].0, "Host");
2384            assert_eq!(headers[0].1, b"example.org");
2385            assert!(eof);
2386        }
2387    }
2388
2389    #[test]
2390    fn test_bad_utf8_in_path() {
2391        const BUF: &[u8] =
2392            b"GET /test?post=I\xE2msorryIforkedyou HTTP/1.1\r\nHost: example.org\r\n\r\n";
2393
2394        let mut req = Request::default();
2395        assert!(req.parse(BUF).unwrap().is_complete());
2396        assert!(str::from_utf8(&BUF[req.path.start..req.path.end]).is_err());
2397    }
2398
2399    /// STATEMENT: `Request::path_ascii` reports whether the request target is
2400    /// pure ASCII, including targets completed across `Partial` results.
2401    ///
2402    /// HOW:
2403    /// - Parse ASCII targets shorter and longer than a SIMD block and check the
2404    ///   flag is set.
2405    /// - Parse targets with a high byte at the start, middle and end, and check
2406    ///   the flag is cleared even when the request reuses a previous `Request`.
2407    /// - Feed a non-ASCII target in two pieces through `parse_with_state` and
2408    ///   check the flag once the line completes.
2409    #[test]
2410    fn test_path_ascii() {
2411        let long = "/a".repeat(40);
2412        let mut req = Request::default();
2413        for path in ["/", "/baseline11?a=13&b=42", long.as_str()] {
2414            let buf = format!("GET {path} HTTP/1.1\r\n");
2415            assert!(req.parse(buf.as_bytes()).unwrap().is_complete());
2416            assert!(req.path_ascii, "{path}");
2417        }
2418
2419        let long = [b"/".repeat(40), b"\xC3\xA9".to_vec(), b"/".repeat(40)].concat();
2420        for path in [&b"/\xC3\xA9"[..], b"\xFF/a?b", b"/a?b=\x80", &long] {
2421            req.path_ascii = true;
2422            let buf = [b"GET ", path, b" HTTP/1.1\r\n"].concat();
2423            assert!(req.parse(&buf).unwrap().is_complete());
2424            assert!(!req.path_ascii, "{path:?}");
2425        }
2426
2427        const BUF: &[u8] = b"GET /caf\xC3\xA9?q=1 HTTP/1.1\r\n";
2428        let mut req = Request {
2429            path_ascii: true,
2430            ..Request::default()
2431        };
2432        let mut st = State::default();
2433        assert_eq!(
2434            req.parse_with_state(&BUF[..9], &mut st),
2435            Ok(Status::Partial)
2436        );
2437        assert!(req.parse_with_state(BUF, &mut st).unwrap().is_complete());
2438        assert!(!req.path_ascii);
2439        assert_eq!(&BUF[req.path.start..req.path.end], b"/caf\xC3\xA9?q=1");
2440    }
2441
2442    /// STATEMENT: `Request::query` is the position of the first `?` of the
2443    /// request target, for ASCII and non-ASCII targets, whole or resumed.
2444    ///
2445    /// HOW:
2446    /// - Parse targets with no `?`, one or two `?` at offsets around the SIMD
2447    ///   block sizes, and high bytes before or after the `?`, reusing one
2448    ///   `Request`, and compare `query` and `path_ascii` with a scalar search.
2449    /// - Feed each request through `parse_with_state` one prefix length at a
2450    ///   time and check the completed result matches the one-shot parse.
2451    #[test]
2452    fn test_request_query() {
2453        let mut targets: Vec<Vec<u8>> = vec![
2454            b"/".to_vec(),
2455            b"?".to_vec(),
2456            b"/a?".to_vec(),
2457            b"/a?b?c".to_vec(),
2458            b"/\xC3\xA9?q=1".to_vec(),
2459            b"/q?\xC3\xA9".to_vec(),
2460            b"/\xC3\xA9/no-query".to_vec(),
2461            b"/baseline11?a=13&b=42".to_vec(),
2462        ];
2463        for pos in [1, 7, 8, 15, 16, 17, 31, 32, 33, 63, 64, 65] {
2464            let mut t = vec![b'/'; 70];
2465            t[pos] = b'?';
2466            targets.push(t.clone());
2467            t[pos + 3] = b'?';
2468            targets.push(t.clone());
2469            t[pos / 2] = 0x80;
2470            targets.push(t);
2471        }
2472
2473        let mut req = Request::default();
2474        for target in &targets {
2475            let buf = [b"GET ", &target[..], b" HTTP/1.1\r\n"].concat();
2476            let query = target.iter().position(|&b| b == b'?').map(|i| i + 4);
2477            let ascii = target.is_ascii();
2478
2479            assert!(req.parse(&buf).unwrap().is_complete());
2480            assert_eq!(&buf[req.path.start..req.path.end], &target[..]);
2481            assert_eq!(req.query, query, "{target:?}");
2482            assert_eq!(req.path_ascii, ascii, "{target:?}");
2483
2484            let mut resumed = Request::default();
2485            let mut st = State::default();
2486            for n in 1..buf.len() {
2487                assert_eq!(
2488                    resumed.parse_with_state(&buf[..n], &mut st),
2489                    Ok(Status::Partial)
2490                );
2491            }
2492            assert!(
2493                resumed
2494                    .parse_with_state(&buf, &mut st)
2495                    .unwrap()
2496                    .is_complete()
2497            );
2498            assert_eq!(resumed.path, req.path);
2499            assert_eq!(resumed.query, query, "resumed {target:?}");
2500            assert_eq!(resumed.path_ascii, ascii, "resumed {target:?}");
2501        }
2502    }
2503
2504    #[test]
2505    fn test_parse_uri_delimiter() {
2506        for input in [&b"/path "[..], b"/path   ", b"/path HTTP/1.1\r\n"] {
2507            assert_eq!(parse_uri(input), Ok(Status::Complete("/path")));
2508        }
2509        assert_eq!(parse_uri(b"/path"), Ok(Status::Partial));
2510    }
2511
2512    #[test]
2513    fn test_parse_uri_utf8() {
2514        assert_eq!(
2515            parse_uri(b"/caf\xc3\xa9 "),
2516            Ok(Status::Complete("/caf\u{e9}"))
2517        );
2518        assert_eq!(parse_uri(b"/\xff "), Err(Error::Token));
2519        assert_eq!(parse_uri(b"/\xc3 "), Err(Error::Token));
2520    }
2521
2522    #[rustfmt::skip]
2523    res! {
2524        test_response_bench,
2525        b"\
2526HTTP/1.0 200 OK\r\n\
2527Date: Wed, 21 Oct 2015 07:28:00 GMT\r\n\
2528Set-Cookie: session=60; user_id=1\r\n\r\n",
2529        |len, version, code, reason, headers, eof| {
2530            assert_eq!(len, 91);
2531            assert_eq!(version, 0);
2532            assert_eq!(code, 200);
2533            assert_eq!(reason, "OK");
2534            assert_eq!(headers.len(), 2);
2535            assert_eq!(headers[0].0, "Date");
2536            assert_eq!(headers[0].1, b"Wed, 21 Oct 2015 07:28:00 GMT");
2537            assert_eq!(headers[1].0, "Set-Cookie");
2538            assert_eq!(headers[1].1, b"session=60; user_id=1");
2539            assert!(eof);
2540        }
2541    }
2542}