Skip to main content

ntex_httparse/
lib.rs

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