Coverage Report

Created: 2025-08-26 06:46

/rust/registry/src/index.crates.io-6f17d22bba15001f/httparse-1.10.1/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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
28
use core::{fmt, mem, result, str};
29
use core::mem::MaybeUninit;
30
31
use crate::iter::Bytes;
32
33
mod iter;
34
#[macro_use] mod macros;
35
mod 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
40
pub 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]
58
0
fn is_method_token(b: u8) -> bool {
59
0
    match b {
60
        // For the majority case, this can be faster than the table lookup.
61
0
        b'A'..=b'Z' => true,
62
0
        _ => TOKEN_MAP[b as usize],
63
    }
64
0
}
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?
69
static URI_MAP: [bool; 256] = byte_map!(
70
    b'!'..=0x7e | 0x80..=0xFF
71
);
72
73
#[inline]
74
0
pub(crate) fn is_uri_token(b: u8) -> bool {
75
0
    URI_MAP[b as usize]
76
0
}
77
78
static 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]
85
0
pub(crate) fn is_header_name_token(b: u8) -> bool {
86
0
    TOKEN_MAP[b as usize]
87
0
}
88
89
90
static HEADER_VALUE_MAP: [bool; 256] = byte_map!(
91
    b'\t' | b' '..=0x7e | 0x80..=0xFF
92
);
93
94
95
#[inline]
96
0
pub(crate) fn is_header_value_token(b: u8) -> bool {
97
0
    HEADER_VALUE_MAP[b as usize]
98
0
}
99
100
/// An error in parsing.
101
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
102
pub 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
119
impl Error {
120
    #[inline]
121
0
    fn description_str(&self) -> &'static str {
122
0
        match *self {
123
0
            Error::HeaderName => "invalid header name",
124
0
            Error::HeaderValue => "invalid header value",
125
0
            Error::NewLine => "invalid new line",
126
0
            Error::Status => "invalid response status",
127
0
            Error::Token => "invalid token",
128
0
            Error::TooManyHeaders => "too many headers",
129
0
            Error::Version => "invalid HTTP version",
130
        }
131
0
    }
132
}
133
134
impl fmt::Display for Error {
135
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136
0
        f.write_str(self.description_str())
137
0
    }
138
}
139
140
#[cfg(feature = "std")]
141
impl std::error::Error for Error {
142
0
    fn description(&self) -> &str {
143
0
        self.description_str()
144
0
    }
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)]
150
pub struct InvalidChunkSize;
151
152
impl fmt::Display for InvalidChunkSize {
153
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154
0
        f.write_str("invalid chunk size")
155
0
    }
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)`.
163
pub 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)]
171
pub enum Status<T> {
172
    /// The completed result.
173
    Complete(T),
174
    /// A partial result.
175
    Partial
176
}
177
178
impl<T> Status<T> {
179
    /// Convenience method to check if status is complete.
180
    #[inline]
181
0
    pub fn is_complete(&self) -> bool {
182
0
        match *self {
183
0
            Status::Complete(..) => true,
184
0
            Status::Partial => false
185
        }
186
0
    }
187
188
    /// Convenience method to check if status is partial.
189
    #[inline]
190
0
    pub fn is_partial(&self) -> bool {
191
0
        match *self {
192
0
            Status::Complete(..) => false,
193
0
            Status::Partial => true
194
        }
195
0
    }
196
197
    /// Convenience method to unwrap a Complete value. Panics if the status is
198
    /// `Partial`.
199
    #[inline]
200
0
    pub fn unwrap(self) -> T {
201
0
        match self {
202
0
            Status::Complete(t) => t,
203
0
            Status::Partial => panic!("Tried to unwrap Status::Partial")
204
        }
205
0
    }
206
}
207
208
/// Parser configuration.
209
#[derive(Clone, Debug, Default)]
210
pub 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
220
impl ParserConfig {
221
    /// Sets whether spaces and tabs should be allowed after header names in responses.
222
0
    pub fn allow_spaces_after_header_name_in_responses(
223
0
        &mut self,
224
0
        value: bool,
225
0
    ) -> &mut Self {
226
0
        self.allow_spaces_after_header_name_in_responses = value;
227
0
        self
228
0
    }
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
0
    pub fn allow_multiple_spaces_in_request_line_delimiters(&mut self, value: bool) -> &mut Self {
244
0
        self.allow_multiple_spaces_in_request_line_delimiters = value;
245
0
        self
246
0
    }
247
248
    /// Whether multiple spaces are allowed as delimiters in request lines.
249
0
    pub fn multiple_spaces_in_request_line_delimiters_are_allowed(&self) -> bool {
250
0
        self.allow_multiple_spaces_in_request_line_delimiters
251
0
    }
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
0
    pub fn allow_multiple_spaces_in_response_status_delimiters(&mut self, value: bool) -> &mut Self {
268
0
        self.allow_multiple_spaces_in_response_status_delimiters = value;
269
0
        self
270
0
    }
271
272
    /// Whether multiple spaces are allowed as delimiters in response status lines.
273
0
    pub fn multiple_spaces_in_response_status_delimiters_are_allowed(&self) -> bool {
274
0
        self.allow_multiple_spaces_in_response_status_delimiters
275
0
    }
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
0
    pub fn allow_obsolete_multiline_headers_in_responses(
301
0
        &mut self,
302
0
        value: bool,
303
0
    ) -> &mut Self {
304
0
        self.allow_obsolete_multiline_headers_in_responses = value;
305
0
        self
306
0
    }
307
308
    /// Whether obsolete multiline headers should be allowed.
309
0
    pub fn obsolete_multiline_headers_in_responses_are_allowed(&self) -> bool {
310
0
        self.allow_obsolete_multiline_headers_in_responses
311
0
    }
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
0
    pub fn allow_space_before_first_header_name(&mut self, value: bool) -> &mut Self {
337
0
        self.allow_space_before_first_header_name = value;
338
0
        self
339
0
    }
340
341
    /// Whether white space before first header is allowed or not
342
0
    pub fn space_before_first_header_name_are_allowed(&self) -> bool {
343
0
        self.allow_space_before_first_header_name
344
0
    }
345
346
    /// Parses a request with the given config.
347
0
    pub fn parse_request<'buf>(
348
0
        &self,
349
0
        request: &mut Request<'_, 'buf>,
350
0
        buf: &'buf [u8],
351
0
    ) -> Result<usize> {
352
0
        request.parse_with_config(buf, self)
353
0
    }
354
355
    /// Parses a request with the given config and buffer for headers
356
0
    pub fn parse_request_with_uninit_headers<'headers, 'buf>(
357
0
        &self,
358
0
        request: &mut Request<'headers, 'buf>,
359
0
        buf: &'buf [u8],
360
0
        headers: &'headers mut [MaybeUninit<Header<'buf>>],
361
0
    ) -> Result<usize> {
362
0
        request.parse_with_config_and_uninit_headers(buf, self, headers)
363
0
    }
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
0
    pub fn ignore_invalid_headers_in_responses(
396
0
        &mut self,
397
0
        value: bool,
398
0
    ) -> &mut Self {
399
0
        self.ignore_invalid_headers_in_responses = value;
400
0
        self
401
0
    }
402
403
    /// Sets whether invalid header lines should be silently ignored in requests.
404
0
    pub fn ignore_invalid_headers_in_requests(
405
0
        &mut self,
406
0
        value: bool,
407
0
    ) -> &mut Self {
408
0
        self.ignore_invalid_headers_in_requests = value;
409
0
        self
410
0
    }
411
412
    /// Parses a response with the given config.
413
0
    pub fn parse_response<'buf>(
414
0
        &self,
415
0
        response: &mut Response<'_, 'buf>,
416
0
        buf: &'buf [u8],
417
0
    ) -> Result<usize> {
418
0
        response.parse_with_config(buf, self)
419
0
    }
420
421
    /// Parses a response with the given config and buffer for headers
422
0
    pub fn parse_response_with_uninit_headers<'headers, 'buf>(
423
0
        &self,
424
0
        response: &mut Response<'headers, 'buf>,
425
0
        buf: &'buf [u8],
426
0
        headers: &'headers mut [MaybeUninit<Header<'buf>>],
427
0
    ) -> Result<usize> {
428
0
        response.parse_with_config_and_uninit_headers(buf, self, headers)
429
0
    }
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)]
458
pub 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
469
impl<'h, 'b> Request<'h, 'b> {
470
    /// Creates a new Request, using a slice of headers you allocate.
471
    #[inline]
472
0
    pub fn new(headers: &'h mut [Header<'b>]) -> Request<'h, 'b> {
473
0
        Request {
474
0
            method: None,
475
0
            path: None,
476
0
            version: None,
477
0
            headers,
478
0
        }
479
0
    }
Unexecuted instantiation: <httparse::Request>::new
Unexecuted instantiation: <httparse::Request>::new
480
481
0
    fn parse_with_config_and_uninit_headers(
482
0
        &mut self,
483
0
        buf: &'b [u8],
484
0
        config: &ParserConfig,
485
0
        mut headers: &'h mut [MaybeUninit<Header<'b>>],
486
0
    ) -> Result<usize> {
487
0
        let orig_len = buf.len();
488
0
        let mut bytes = Bytes::new(buf);
489
0
        complete!(skip_empty_lines(&mut bytes));
490
0
        let method = complete!(parse_method(&mut bytes));
491
0
        self.method = Some(method);
492
0
        if config.allow_multiple_spaces_in_request_line_delimiters {
493
0
            complete!(skip_spaces(&mut bytes));
494
0
        }
495
0
        self.path = Some(complete!(parse_uri(&mut bytes)));
496
0
        if config.allow_multiple_spaces_in_request_line_delimiters {
497
0
            complete!(skip_spaces(&mut bytes));
498
0
        }
499
0
        self.version = Some(complete!(parse_version(&mut bytes)));
500
0
        newline!(bytes);
501
502
0
        let len = orig_len - bytes.len();
503
0
        let headers_len = complete!(parse_headers_iter_uninit(
504
0
            &mut headers,
505
0
            &mut bytes,
506
0
            &HeaderParserConfig {
507
0
                allow_spaces_after_header_name: false,
508
0
                allow_obsolete_multiline_headers: false,
509
0
                allow_space_before_first_header_name: config.allow_space_before_first_header_name,
510
0
                ignore_invalid_headers: config.ignore_invalid_headers_in_requests
511
0
            },
512
0
        ));
513
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
514
0
        self.headers = unsafe { assume_init_slice(headers) };
515
0
516
0
        Ok(Status::Complete(len + headers_len))
517
0
    }
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
0
    pub fn parse_with_uninit_headers(
524
0
        &mut self,
525
0
        buf: &'b [u8],
526
0
        headers: &'h mut [MaybeUninit<Header<'b>>],
527
0
    ) -> Result<usize> {
528
0
        self.parse_with_config_and_uninit_headers(buf, &Default::default(), headers)
529
0
    }
530
531
0
    fn parse_with_config(&mut self, buf: &'b [u8], config: &ParserConfig) -> Result<usize> {
532
0
        let headers = mem::take(&mut self.headers);
533
0
534
0
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
535
0
        unsafe {
536
0
            let headers: *mut [Header<'_>] = headers;
537
0
            let headers = headers as *mut [MaybeUninit<Header<'_>>];
538
0
            match self.parse_with_config_and_uninit_headers(buf, config, &mut *headers) {
539
0
                Ok(Status::Complete(idx)) => Ok(Status::Complete(idx)),
540
0
                other => {
541
0
                    // put the original headers back
542
0
                    self.headers = &mut *(headers as *mut [Header<'_>]);
543
0
                    other
544
                },
545
            }
546
        }
547
0
    }
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
0
    pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> {
553
0
        self.parse_with_config(buf, &Default::default())
554
0
    }
555
}
556
557
#[inline]
558
0
fn skip_empty_lines(bytes: &mut Bytes<'_>) -> Result<()> {
559
    loop {
560
0
        let b = bytes.peek();
561
0
        match b {
562
            Some(b'\r') => {
563
                // SAFETY: peeked and found `\r`, so it's safe to bump 1 pos
564
0
                unsafe { bytes.bump() };
565
0
                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
0
                unsafe {
570
0
                    bytes.bump();
571
0
                }
572
            }
573
            Some(..) => {
574
0
                bytes.slice();
575
0
                return Ok(Status::Complete(()));
576
            }
577
0
            None => return Ok(Status::Partial),
578
        }
579
    }
580
0
}
581
582
#[inline]
583
0
fn skip_spaces(bytes: &mut Bytes<'_>) -> Result<()> {
584
    loop {
585
0
        let b = bytes.peek();
586
0
        match b {
587
0
            Some(b' ') => {
588
0
                // SAFETY: peeked and found ` `, so it's safe to bump 1 pos
589
0
                unsafe { bytes.bump() };
590
0
            }
591
            Some(..) => {
592
0
                bytes.slice();
593
0
                return Ok(Status::Complete(()));
594
            }
595
0
            None => return Ok(Status::Partial),
596
        }
597
    }
598
0
}
599
600
/// A parsed Response.
601
///
602
/// See `Request` docs for explanation of optional values.
603
#[derive(Debug, Eq, PartialEq)]
604
pub 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
617
impl<'h, 'b> Response<'h, 'b> {
618
    /// Creates a new `Response` using a slice of `Header`s you have allocated.
619
    #[inline]
620
0
    pub fn new(headers: &'h mut [Header<'b>]) -> Response<'h, 'b> {
621
0
        Response {
622
0
            version: None,
623
0
            code: None,
624
0
            reason: None,
625
0
            headers,
626
0
        }
627
0
    }
Unexecuted instantiation: <httparse::Response>::new
Unexecuted instantiation: <httparse::Response>::new
628
629
    /// Try to parse a buffer of bytes into this `Response`.
630
0
    pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> {
631
0
        self.parse_with_config(buf, &ParserConfig::default())
632
0
    }
633
634
0
    fn parse_with_config(&mut self, buf: &'b [u8], config: &ParserConfig) -> Result<usize> {
635
0
        let headers = mem::take(&mut self.headers);
636
0
637
0
        // SAFETY: see guarantees of [`parse_headers_iter_uninit`], which leaves no uninitialized
638
0
        // headers around. On failure, the original headers are restored.
639
0
        unsafe {
640
0
            let headers: *mut [Header<'_>] = headers;
641
0
            let headers = headers as *mut [MaybeUninit<Header<'_>>];
642
0
            match self.parse_with_config_and_uninit_headers(buf, config, &mut *headers) {
643
0
                Ok(Status::Complete(idx)) => Ok(Status::Complete(idx)),
644
0
                other => {
645
0
                    // put the original headers back
646
0
                    self.headers = &mut *(headers as *mut [Header<'_>]);
647
0
                    other
648
                },
649
            }
650
        }
651
0
    }
652
653
0
    fn parse_with_config_and_uninit_headers(
654
0
        &mut self,
655
0
        buf: &'b [u8],
656
0
        config: &ParserConfig,
657
0
        mut headers: &'h mut [MaybeUninit<Header<'b>>],
658
0
    ) -> Result<usize> {
659
0
        let orig_len = buf.len();
660
0
        let mut bytes = Bytes::new(buf);
661
0
662
0
        complete!(skip_empty_lines(&mut bytes));
663
0
        self.version = Some(complete!(parse_version(&mut bytes)));
664
0
        space!(bytes or Error::Version);
665
0
        if config.allow_multiple_spaces_in_response_status_delimiters {
666
0
            complete!(skip_spaces(&mut bytes));
667
0
        }
668
0
        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
0
        match next!(bytes) {
680
            b' ' => {
681
0
                if config.allow_multiple_spaces_in_response_status_delimiters {
682
0
                    complete!(skip_spaces(&mut bytes));
683
0
                }
684
0
                bytes.slice();
685
0
                self.reason = Some(complete!(parse_reason(&mut bytes)));
686
            },
687
            b'\r' => {
688
0
                expect!(bytes.next() == b'\n' => Err(Error::Status));
689
0
                bytes.slice();
690
0
                self.reason = Some("");
691
            },
692
0
            b'\n' => {
693
0
                bytes.slice();
694
0
                self.reason = Some("");
695
0
            }
696
0
            _ => return Err(Error::Status),
697
        }
698
699
700
0
        let len = orig_len - bytes.len();
701
0
        let headers_len = complete!(parse_headers_iter_uninit(
702
0
            &mut headers,
703
0
            &mut bytes,
704
0
            &HeaderParserConfig {
705
0
                allow_spaces_after_header_name: config.allow_spaces_after_header_name_in_responses,
706
0
                allow_obsolete_multiline_headers: config.allow_obsolete_multiline_headers_in_responses,
707
0
                allow_space_before_first_header_name: config.allow_space_before_first_header_name,
708
0
                ignore_invalid_headers: config.ignore_invalid_headers_in_responses
709
0
            }
710
0
        ));
711
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
712
0
        self.headers = unsafe { assume_init_slice(headers) };
713
0
        Ok(Status::Complete(len + headers_len))
714
0
    }
715
}
716
717
/// Represents a parsed header.
718
#[derive(Copy, Clone, Eq, PartialEq)]
719
pub 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
731
impl fmt::Debug for Header<'_> {
732
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
733
0
        let mut f = f.debug_struct("Header");
734
0
        f.field("name", &self.name);
735
0
        if let Ok(value) = str::from_utf8(self.value) {
736
0
            f.field("value", &value);
737
0
        } else {
738
0
            f.field("value", &self.value);
739
0
        }
740
0
        f.finish()
741
0
    }
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
/// ```
752
pub 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
758
0
pub fn parse_version(bytes: &mut Bytes) -> Result<u8> {
759
0
    if let Some(eight) = bytes.peek_n::<[u8; 8]>(8) {
760
        // NOTE: should be const once MSRV >= 1.44
761
0
        let h10: u64 = u64::from_ne_bytes(*b"HTTP/1.0");
762
0
        let h11: u64 = u64::from_ne_bytes(*b"HTTP/1.1");
763
0
        // SAFETY: peek_n(8) before ensure within bounds
764
0
        unsafe {
765
0
            bytes.advance(8);
766
0
        }
767
0
        let block = u64::from_ne_bytes(eight);
768
0
        // NOTE: should be match once h10 & h11 are consts
769
0
        return if block == h10 {
770
0
            Ok(Status::Complete(0))
771
0
        } else if block == h11 {
772
0
            Ok(Status::Complete(1))
773
        } else {
774
0
            Err(Error::Version)
775
        };
776
0
    }
777
0
778
0
    // else (but not in `else` because of borrow checker)
779
0
780
0
    // If there aren't at least 8 bytes, we still want to detect early
781
0
    // if this is a valid version or not. If it is, we'll return Partial.
782
0
    expect!(bytes.next() == b'H' => Err(Error::Version));
783
0
    expect!(bytes.next() == b'T' => Err(Error::Version));
784
0
    expect!(bytes.next() == b'T' => Err(Error::Version));
785
0
    expect!(bytes.next() == b'P' => Err(Error::Version));
786
0
    expect!(bytes.next() == b'/' => Err(Error::Version));
787
0
    expect!(bytes.next() == b'1' => Err(Error::Version));
788
0
    expect!(bytes.next() == b'.' => Err(Error::Version));
789
0
    Ok(Status::Partial)
790
0
}
791
792
#[inline]
793
#[doc(hidden)]
794
#[allow(missing_docs)]
795
// WARNING: Exported for internal benchmarks, not fit for public consumption
796
0
pub 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
0
    match bytes.peek_n::<[u8; 4]>(4) {
800
        Some(GET) => {
801
            // SAFETY: we matched "GET " which has 4 bytes and is ASCII
802
0
            let method = unsafe {
803
0
                bytes.advance(4); // advance cursor past "GET "
804
0
                str::from_utf8_unchecked(bytes.slice_skip(1)) // "GET" without space
805
0
            };
806
0
            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
0
        Some(POST) if unsafe { bytes.peek_ahead(4) } == Some(b' ') => {
814
0
            // SAFETY: we matched "POST " which has 5 bytes
815
0
            let method = unsafe {
816
0
                bytes.advance(5); // advance cursor past "POST "
817
0
                str::from_utf8_unchecked(bytes.slice_skip(1)) // "POST" without space
818
0
            };
819
0
            Ok(Status::Complete(method))
820
        }
821
0
        _ => parse_token(bytes),
822
    }
823
0
}
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]
839
0
fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
840
0
    let mut seen_obs_text = false;
841
    loop {
842
0
        let b = next!(bytes);
843
0
        if b == b'\r' {
844
0
            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
0
                    let bytes = bytes.slice_skip(2);
853
0
                    if !seen_obs_text {
854
                        // all bytes up till `i` must have been HTAB / SP / VCHAR
855
0
                        str::from_utf8_unchecked(bytes)
856
                    } else {
857
                        // obs-text characters were found, so return the fallback empty string
858
0
                        ""
859
                    }
860
                },
861
            ));
862
0
        } 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
0
                    let bytes = bytes.slice_skip(1);
869
0
                    if !seen_obs_text {
870
                        // all bytes up till `i` must have been HTAB / SP / VCHAR
871
0
                        str::from_utf8_unchecked(bytes)
872
                    } else {
873
                        // obs-text characters were found, so return the fallback empty string
874
0
                        ""
875
                    }
876
                },
877
            ));
878
0
        } else if !(b == 0x09 || b == b' ' || (0x21..=0x7E).contains(&b) || b >= 0x80) {
879
0
            return Err(Error::Status);
880
0
        } else if b >= 0x80 {
881
0
            seen_obs_text = true;
882
0
        }
883
    }
884
0
}
885
886
#[inline]
887
0
fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
888
0
    let b = next!(bytes);
889
0
    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
0
        return Err(Error::Token);
892
0
    }
893
894
    loop {
895
0
        let b = next!(bytes);
896
0
        if b == b' ' {
897
0
            return Ok(Status::Complete(
898
0
                // SAFETY: all bytes up till `i` must have been `is_method_token` and therefore also utf-8.
899
0
                unsafe { str::from_utf8_unchecked(bytes.slice_skip(1)) },
900
0
            ));
901
0
        } else if !is_method_token(b) {
902
0
            return Err(Error::Token);
903
0
        }
904
    }
905
0
}
906
907
#[inline]
908
#[doc(hidden)]
909
#[allow(missing_docs)]
910
// WARNING: Exported for internal benchmarks, not fit for public consumption
911
0
pub fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
912
0
    let start = bytes.pos();
913
0
    simd::match_uri_vectored(bytes);
914
0
    let end = bytes.pos();
915
0
916
0
    if next!(bytes) == b' ' {
917
        // URI must have at least one char
918
0
        if end == start {
919
0
            return Err(Error::Token);
920
0
        }
921
0
922
0
        // SAFETY: all bytes up till `i` must have been `is_token` and therefore also utf-8.
923
0
        match str::from_utf8(unsafe { bytes.slice_skip(1) }) {
924
0
            Ok(uri) => Ok(Status::Complete(uri)),
925
0
            Err(_) => Err(Error::Token),
926
        }
927
    } else {
928
0
        Err(Error::Token)
929
    }
930
0
}
931
932
#[inline]
933
0
fn parse_code(bytes: &mut Bytes<'_>) -> Result<u16> {
934
0
    let hundreds = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
935
0
    let tens = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
936
0
    let ones = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
937
938
0
    Ok(Status::Complete((hundreds - b'0') as u16 * 100 +
939
0
        (tens - b'0') as u16 * 10 +
940
0
        (ones - b'0') as u16))
941
0
}
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
/// ```
961
0
pub fn parse_headers<'b: 'h, 'h>(
962
0
    src: &'b [u8],
963
0
    mut dst: &'h mut [Header<'b>],
964
0
) -> Result<(usize, &'h [Header<'b>])> {
965
0
    let mut iter = Bytes::new(src);
966
0
    let pos = complete!(parse_headers_iter(&mut dst, &mut iter, &HeaderParserConfig::default()));
967
0
    Ok(Status::Complete((pos, dst)))
968
0
}
969
970
#[inline]
971
0
fn parse_headers_iter<'a>(
972
0
    headers: &mut &mut [Header<'a>],
973
0
    bytes: &mut Bytes<'a>,
974
0
    config: &HeaderParserConfig,
975
0
) -> Result<usize> {
976
0
    parse_headers_iter_uninit(
977
0
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
978
0
        unsafe { deinit_slice_mut(headers) },
979
0
        bytes,
980
0
        config,
981
0
    )
982
0
}
983
984
0
unsafe fn deinit_slice_mut<'a, 'b, T>(s: &'a mut &'b mut [T]) -> &'a mut &'b mut [MaybeUninit<T>] {
985
0
    let s: *mut &mut [T] = s;
986
0
    let s = s as *mut &mut [MaybeUninit<T>];
987
0
    &mut *s
988
0
}
989
0
unsafe fn assume_init_slice<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] {
990
0
    let s: *mut [MaybeUninit<T>] = s;
991
0
    let s = s as *mut [T];
992
0
    &mut *s
993
0
}
994
995
#[derive(Clone, Debug, Default)]
996
struct 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
 */
1012
0
fn parse_headers_iter_uninit<'a>(
1013
0
    headers: &mut &mut [MaybeUninit<Header<'a>>],
1014
0
    bytes: &mut Bytes<'a>,
1015
0
    config: &HeaderParserConfig
1016
0
) -> 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
0
        fn drop(&mut self) {
1029
0
            let headers = mem::take(self.headers);
1030
0
1031
0
            /* SAFETY: num_headers is the number of initialized headers */
1032
0
            let headers = unsafe { headers.get_unchecked_mut(..self.num_headers) };
1033
0
1034
0
            *self.headers = headers;
1035
0
        }
1036
    }
1037
1038
0
    let mut autoshrink = ShrinkOnDrop {
1039
0
        headers,
1040
0
        num_headers: 0,
1041
0
    };
1042
0
    // Track starting pointer to calculate the number of bytes parsed.
1043
0
    let start = bytes.as_ref().as_ptr() as usize;
1044
0
    let mut result = Err(Error::TooManyHeaders);
1045
0
1046
0
    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
0
    'headers: loop {
1074
0
        // Return the error `$err` if `ignore_invalid_headers_in_responses`
1075
0
        // is false, otherwise find the end of the current line and resume
1076
0
        // parsing on the next one.
1077
0
        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
0
        let b = next!(bytes);
1107
0
        if b == b'\r' {
1108
0
            expect!(bytes.next() == b'\n' => Err(Error::NewLine));
1109
0
            let end = bytes.as_ref().as_ptr() as usize;
1110
0
            result = Ok(Status::Complete(end - start));
1111
0
            break;
1112
0
        }
1113
0
        if b == b'\n' {
1114
0
            let end = bytes.as_ref().as_ptr() as usize;
1115
0
            result = Ok(Status::Complete(end - start));
1116
0
            break;
1117
0
        }
1118
0
        if !is_header_name_token(b) {
1119
0
            if config.allow_space_before_first_header_name
1120
0
                && autoshrink.num_headers == 0
1121
0
                && (b == b' ' || b == b'\t')
1122
            {
1123
                //advance past white space and then try parsing header again
1124
0
                while let Some(peek) = bytes.peek() {
1125
0
                    if peek == b' ' || peek == b'\t' {
1126
0
                        next!(bytes);
1127
                    } else {
1128
0
                        break;
1129
                    }
1130
                }
1131
0
                bytes.slice();
1132
0
                continue 'headers;
1133
            } else {
1134
0
                handle_invalid_char!(bytes, b, HeaderName);
1135
            }
1136
0
        }
1137
1138
        #[allow(clippy::never_loop)]
1139
        // parse header name until colon
1140
0
        let header_name: &str = 'name: loop {
1141
0
            simd::match_header_name_vectored(bytes);
1142
0
            let mut b = next!(bytes);
1143
1144
            // SAFETY: previously bumped by 1 with next! -> always safe.
1145
0
            let bslice = unsafe { bytes.slice_skip(1) };
1146
0
            // SAFETY: previous call to match_header_name_vectored ensured all bytes are valid
1147
0
            // header name chars, and as such also valid utf-8.
1148
0
            let name = unsafe { str::from_utf8_unchecked(bslice) };
1149
0
1150
0
            if b == b':' {
1151
0
                break 'name name;
1152
0
            }
1153
0
1154
0
            if config.allow_spaces_after_header_name {
1155
0
                while b == b' ' || b == b'\t' {
1156
0
                    b = next!(bytes);
1157
1158
0
                    if b == b':' {
1159
0
                        bytes.slice();
1160
0
                        break 'name name;
1161
0
                    }
1162
                }
1163
0
            }
1164
1165
0
            handle_invalid_char!(bytes, b, HeaderName);
1166
        };
1167
1168
        let mut b;
1169
1170
        #[allow(clippy::never_loop)]
1171
0
        let value_slice = 'value: loop {
1172
            // eat white space between colon and value
1173
            'whitespace_after_colon: loop {
1174
0
                b = next!(bytes);
1175
0
                if b == b' ' || b == b'\t' {
1176
0
                    bytes.slice();
1177
0
                    continue 'whitespace_after_colon;
1178
0
                }
1179
0
                if is_header_value_token(b) {
1180
0
                    break 'whitespace_after_colon;
1181
0
                }
1182
0
1183
0
                if b == b'\r' {
1184
0
                    expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
1185
0
                } else if b != b'\n' {
1186
0
                    handle_invalid_char!(bytes, b, HeaderValue);
1187
0
                }
1188
1189
0
                maybe_continue_after_obsolete_line_folding!(bytes, 'whitespace_after_colon);
1190
1191
0
                let whitespace_slice = bytes.slice();
1192
0
1193
0
                // This produces an empty slice that points to the beginning
1194
0
                // of the whitespace.
1195
0
                break 'value &whitespace_slice[0..0];
1196
            }
1197
1198
            'value_lines: loop {
1199
                // parse value till EOL
1200
1201
0
                simd::match_header_value_vectored(bytes);
1202
0
                let b = next!(bytes);
1203
1204
                //found_ctl
1205
0
                let skip = if b == b'\r' {
1206
0
                    expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
1207
0
                    2
1208
0
                } else if b == b'\n' {
1209
0
                    1
1210
                } else {
1211
0
                    handle_invalid_char!(bytes, b, HeaderValue);
1212
                };
1213
1214
0
                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
0
                    break 'value bytes.slice_skip(skip);
1219
                }
1220
            }
1221
        };
1222
1223
0
        let uninit_header = match iter.next() {
1224
0
            Some(header) => header,
1225
0
            None => break 'headers
1226
        };
1227
1228
        // trim trailing whitespace in the header
1229
0
        let header_value = if let Some(last_visible) = value_slice
1230
0
            .iter()
1231
0
            .rposition(|b| *b != b' ' && *b != b'\t' && *b != b'\r' && *b != b'\n')
1232
        {
1233
            // There is at least one non-whitespace character.
1234
0
            &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
0
            value_slice
1239
        };
1240
1241
0
        *uninit_header = MaybeUninit::new(Header {
1242
0
            name: header_name,
1243
0
            value: header_value,
1244
0
        });
1245
0
        autoshrink.num_headers += 1;
1246
    }
1247
1248
0
    result
1249
0
}
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
/// ```
1263
0
pub fn parse_chunk_size(buf: &[u8])
1264
0
    -> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
1265
    const RADIX: u64 = 16;
1266
0
    let mut bytes = Bytes::new(buf);
1267
0
    let mut size = 0;
1268
0
    let mut in_chunk_size = true;
1269
0
    let mut in_ext = false;
1270
0
    let mut count = 0;
1271
    loop {
1272
0
        let b = next!(bytes);
1273
0
        match b {
1274
0
            b'0' ..= b'9' if in_chunk_size => {
1275
0
                if count > 15 {
1276
0
                    return Err(InvalidChunkSize);
1277
0
                }
1278
0
                count += 1;
1279
0
                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
0
                    return Err(InvalidChunkSize);
1285
0
                }
1286
0
                size *= RADIX;
1287
0
                size += (b - b'0') as u64;
1288
            },
1289
0
            b'a' ..= b'f' if in_chunk_size => {
1290
0
                if count > 15 {
1291
0
                    return Err(InvalidChunkSize);
1292
0
                }
1293
0
                count += 1;
1294
0
                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
1295
0
                    return Err(InvalidChunkSize);
1296
0
                }
1297
0
                size *= RADIX;
1298
0
                size += (b + 10 - b'a') as u64;
1299
            }
1300
0
            b'A' ..= b'F' if in_chunk_size => {
1301
0
                if count > 15 {
1302
0
                    return Err(InvalidChunkSize);
1303
0
                }
1304
0
                count += 1;
1305
0
                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
1306
0
                    return Err(InvalidChunkSize);
1307
0
                }
1308
0
                size *= RADIX;
1309
0
                size += (b + 10 - b'A') as u64;
1310
            }
1311
            b'\r' => {
1312
0
                match next!(bytes) {
1313
0
                    b'\n' => break,
1314
0
                    _ => return Err(InvalidChunkSize),
1315
                }
1316
            }
1317
            // If we weren't in the extension yet, the ";" signals its start
1318
0
            b';' if !in_ext => {
1319
0
                in_ext = true;
1320
0
                in_chunk_size = false;
1321
0
            }
1322
            // "Linear white space" is ignored between the chunk size and the
1323
            // extension separator token (";") due to the "implied *LWS rule".
1324
0
            b'\t' | b' ' if !in_ext && !in_chunk_size => {}
1325
            // LWS can follow the chunk size, but no more digits can come
1326
0
            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
0
            _ 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
0
            _ => return Err(InvalidChunkSize),
1336
        }
1337
    }
1338
0
    Ok(Status::Complete((bytes.pos(), size)))
1339
0
}
1340
1341
#[cfg(test)]
1342
mod 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
}