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