httparse/
lib.rs

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