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