Coverage Report

Created: 2025-07-12 06:55

/src/httparse/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
4.22k
fn is_method_token(b: u8) -> bool {
59
4.22k
    match b {
60
        // For the majority case, this can be faster than the table lookup.
61
2.74k
        b'A'..=b'Z' => true,
62
2.50k
        _ => TOKEN_MAP[b as usize],
63
    }
64
4.22k
}
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
1.51k
pub(crate) fn is_uri_token(b: u8) -> bool {
75
1.51k
    URI_MAP[b as usize]
76
1.51k
}
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
133k
pub(crate) fn is_header_name_token(b: u8) -> bool {
86
133k
    TOKEN_MAP[b as usize]
87
133k
}
88
89
90
static HEADER_VALUE_MAP: [bool; 256] = byte_map!(
91
    b'\t' | b' '..=0x7e | 0x80..=0xFF
92
);
93
94
95
#[inline]
96
9.15k
pub(crate) fn is_header_value_token(b: u8) -> bool {
97
9.15k
    HEADER_VALUE_MAP[b as usize]
98
9.15k
}
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
1.08k
    pub fn allow_multiple_spaces_in_request_line_delimiters(&mut self, value: bool) -> &mut Self {
244
1.08k
        self.allow_multiple_spaces_in_request_line_delimiters = value;
245
1.08k
        self
246
1.08k
    }
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
1.18k
    pub fn allow_multiple_spaces_in_response_status_delimiters(&mut self, value: bool) -> &mut Self {
268
1.18k
        self.allow_multiple_spaces_in_response_status_delimiters = value;
269
1.18k
        self
270
1.18k
    }
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
1.08k
    pub fn parse_request<'buf>(
348
1.08k
        &self,
349
1.08k
        request: &mut Request<'_, 'buf>,
350
1.08k
        buf: &'buf [u8],
351
1.08k
    ) -> Result<usize> {
352
1.08k
        request.parse_with_config(buf, self)
353
1.08k
    }
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
1.18k
    pub fn parse_response<'buf>(
414
1.18k
        &self,
415
1.18k
        response: &mut Response<'_, 'buf>,
416
1.18k
        buf: &'buf [u8],
417
1.18k
    ) -> Result<usize> {
418
1.18k
        response.parse_with_config(buf, self)
419
1.18k
    }
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
2.17k
    pub fn new(headers: &'h mut [Header<'b>]) -> Request<'h, 'b> {
473
2.17k
        Request {
474
2.17k
            method: None,
475
2.17k
            path: None,
476
2.17k
            version: None,
477
2.17k
            headers,
478
2.17k
        }
479
2.17k
    }
Unexecuted instantiation: <httparse::Request>::new
<httparse::Request>::new
Line
Count
Source
472
1.08k
    pub fn new(headers: &'h mut [Header<'b>]) -> Request<'h, 'b> {
473
1.08k
        Request {
474
1.08k
            method: None,
475
1.08k
            path: None,
476
1.08k
            version: None,
477
1.08k
            headers,
478
1.08k
        }
479
1.08k
    }
<httparse::Request>::new
Line
Count
Source
472
1.08k
    pub fn new(headers: &'h mut [Header<'b>]) -> Request<'h, 'b> {
473
1.08k
        Request {
474
1.08k
            method: None,
475
1.08k
            path: None,
476
1.08k
            version: None,
477
1.08k
            headers,
478
1.08k
        }
479
1.08k
    }
480
481
2.17k
    fn parse_with_config_and_uninit_headers(
482
2.17k
        &mut self,
483
2.17k
        buf: &'b [u8],
484
2.17k
        config: &ParserConfig,
485
2.17k
        mut headers: &'h mut [MaybeUninit<Header<'b>>],
486
2.17k
    ) -> Result<usize> {
487
2.17k
        let orig_len = buf.len();
488
2.17k
        let mut bytes = Bytes::new(buf);
489
2.17k
        complete!(skip_empty_lines(&mut bytes));
490
2.09k
        let method = complete!(parse_method(&mut bytes));
491
1.78k
        self.method = Some(method);
492
1.78k
        if config.allow_multiple_spaces_in_request_line_delimiters {
493
892
            complete!(skip_spaces(&mut bytes));
494
895
        }
495
1.77k
        self.path = Some(complete!(parse_uri(&mut bytes)));
496
1.61k
        if config.allow_multiple_spaces_in_request_line_delimiters {
497
807
            complete!(skip_spaces(&mut bytes));
498
810
        }
499
1.60k
        self.version = Some(complete!(parse_version(&mut bytes)));
500
804
        newline!(bytes);
501
502
775
        let len = orig_len - bytes.len();
503
775
        let headers_len = complete!(parse_headers_iter_uninit(
504
775
            &mut headers,
505
775
            &mut bytes,
506
775
            &HeaderParserConfig {
507
775
                allow_spaces_after_header_name: false,
508
775
                allow_obsolete_multiline_headers: false,
509
775
                allow_space_before_first_header_name: config.allow_space_before_first_header_name,
510
775
                ignore_invalid_headers: config.ignore_invalid_headers_in_requests
511
775
            },
512
775
        ));
513
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
514
15
        self.headers = unsafe { assume_init_slice(headers) };
515
15
516
15
        Ok(Status::Complete(len + headers_len))
517
2.17k
    }
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
2.17k
    fn parse_with_config(&mut self, buf: &'b [u8], config: &ParserConfig) -> Result<usize> {
532
2.17k
        let headers = mem::take(&mut self.headers);
533
2.17k
534
2.17k
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
535
2.17k
        unsafe {
536
2.17k
            let headers: *mut [Header<'_>] = headers;
537
2.17k
            let headers = headers as *mut [MaybeUninit<Header<'_>>];
538
2.17k
            match self.parse_with_config_and_uninit_headers(buf, config, &mut *headers) {
539
15
                Ok(Status::Complete(idx)) => Ok(Status::Complete(idx)),
540
2.15k
                other => {
541
2.15k
                    // put the original headers back
542
2.15k
                    self.headers = &mut *(headers as *mut [Header<'_>]);
543
2.15k
                    other
544
                },
545
            }
546
        }
547
2.17k
    }
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
1.08k
    pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> {
553
1.08k
        self.parse_with_config(buf, &Default::default())
554
1.08k
    }
555
}
556
557
#[inline]
558
4.46k
fn skip_empty_lines(bytes: &mut Bytes<'_>) -> Result<()> {
559
    loop {
560
7.27k
        let b = bytes.peek();
561
7.27k
        match b {
562
            Some(b'\r') => {
563
                // SAFETY: peeked and found `\r`, so it's safe to bump 1 pos
564
958
                unsafe { bytes.bump() };
565
958
                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
1.92k
                unsafe {
570
1.92k
                    bytes.bump();
571
1.92k
                }
572
            }
573
            Some(..) => {
574
4.31k
                bytes.slice();
575
4.31k
                return Ok(Status::Complete(()));
576
            }
577
82
            None => return Ok(Status::Partial),
578
        }
579
    }
580
4.46k
}
581
582
#[inline]
583
2.43k
fn skip_spaces(bytes: &mut Bytes<'_>) -> Result<()> {
584
    loop {
585
4.09k
        let b = bytes.peek();
586
4.09k
        match b {
587
1.65k
            Some(b' ') => {
588
1.65k
                // SAFETY: peeked and found ` `, so it's safe to bump 1 pos
589
1.65k
                unsafe { bytes.bump() };
590
1.65k
            }
591
            Some(..) => {
592
2.38k
                bytes.slice();
593
2.38k
                return Ok(Status::Complete(()));
594
            }
595
52
            None => return Ok(Status::Partial),
596
        }
597
    }
598
2.43k
}
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
2.29k
    pub fn new(headers: &'h mut [Header<'b>]) -> Response<'h, 'b> {
621
2.29k
        Response {
622
2.29k
            version: None,
623
2.29k
            code: None,
624
2.29k
            reason: None,
625
2.29k
            headers,
626
2.29k
        }
627
2.29k
    }
<httparse::Response>::new
Line
Count
Source
620
1.18k
    pub fn new(headers: &'h mut [Header<'b>]) -> Response<'h, 'b> {
621
1.18k
        Response {
622
1.18k
            version: None,
623
1.18k
            code: None,
624
1.18k
            reason: None,
625
1.18k
            headers,
626
1.18k
        }
627
1.18k
    }
Unexecuted instantiation: <httparse::Response>::new
<httparse::Response>::new
Line
Count
Source
620
1.10k
    pub fn new(headers: &'h mut [Header<'b>]) -> Response<'h, 'b> {
621
1.10k
        Response {
622
1.10k
            version: None,
623
1.10k
            code: None,
624
1.10k
            reason: None,
625
1.10k
            headers,
626
1.10k
        }
627
1.10k
    }
628
629
    /// Try to parse a buffer of bytes into this `Response`.
630
1.10k
    pub fn parse(&mut self, buf: &'b [u8]) -> Result<usize> {
631
1.10k
        self.parse_with_config(buf, &ParserConfig::default())
632
1.10k
    }
633
634
2.29k
    fn parse_with_config(&mut self, buf: &'b [u8], config: &ParserConfig) -> Result<usize> {
635
2.29k
        let headers = mem::take(&mut self.headers);
636
2.29k
637
2.29k
        // SAFETY: see guarantees of [`parse_headers_iter_uninit`], which leaves no uninitialized
638
2.29k
        // headers around. On failure, the original headers are restored.
639
2.29k
        unsafe {
640
2.29k
            let headers: *mut [Header<'_>] = headers;
641
2.29k
            let headers = headers as *mut [MaybeUninit<Header<'_>>];
642
2.29k
            match self.parse_with_config_and_uninit_headers(buf, config, &mut *headers) {
643
16
                Ok(Status::Complete(idx)) => Ok(Status::Complete(idx)),
644
2.27k
                other => {
645
2.27k
                    // put the original headers back
646
2.27k
                    self.headers = &mut *(headers as *mut [Header<'_>]);
647
2.27k
                    other
648
                },
649
            }
650
        }
651
2.29k
    }
652
653
2.29k
    fn parse_with_config_and_uninit_headers(
654
2.29k
        &mut self,
655
2.29k
        buf: &'b [u8],
656
2.29k
        config: &ParserConfig,
657
2.29k
        mut headers: &'h mut [MaybeUninit<Header<'b>>],
658
2.29k
    ) -> Result<usize> {
659
2.29k
        let orig_len = buf.len();
660
2.29k
        let mut bytes = Bytes::new(buf);
661
2.29k
662
2.29k
        complete!(skip_empty_lines(&mut bytes));
663
2.21k
        self.version = Some(complete!(parse_version(&mut bytes)));
664
1.20k
        space!(bytes or Error::Version);
665
1.18k
        if config.allow_multiple_spaces_in_response_status_delimiters {
666
621
            complete!(skip_spaces(&mut bytes));
667
561
        }
668
1.16k
        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
1.03k
        match next!(bytes) {
680
            b' ' => {
681
208
                if config.allow_multiple_spaces_in_response_status_delimiters {
682
116
                    complete!(skip_spaces(&mut bytes));
683
92
                }
684
196
                bytes.slice();
685
196
                self.reason = Some(complete!(parse_reason(&mut bytes)));
686
            },
687
            b'\r' => {
688
39
                expect!(bytes.next() == b'\n' => Err(Error::Status));
689
10
                bytes.slice();
690
10
                self.reason = Some("");
691
            },
692
773
            b'\n' => {
693
773
                bytes.slice();
694
773
                self.reason = Some("");
695
773
            }
696
2
            _ => return Err(Error::Status),
697
        }
698
699
700
817
        let len = orig_len - bytes.len();
701
817
        let headers_len = complete!(parse_headers_iter_uninit(
702
817
            &mut headers,
703
817
            &mut bytes,
704
817
            &HeaderParserConfig {
705
817
                allow_spaces_after_header_name: config.allow_spaces_after_header_name_in_responses,
706
817
                allow_obsolete_multiline_headers: config.allow_obsolete_multiline_headers_in_responses,
707
817
                allow_space_before_first_header_name: config.allow_space_before_first_header_name,
708
817
                ignore_invalid_headers: config.ignore_invalid_headers_in_responses
709
817
            }
710
817
        ));
711
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
712
16
        self.headers = unsafe { assume_init_slice(headers) };
713
16
        Ok(Status::Complete(len + headers_len))
714
2.29k
    }
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
3.81k
pub fn parse_version(bytes: &mut Bytes) -> Result<u8> {
759
3.81k
    if let Some(eight) = bytes.peek_n::<[u8; 8]>(8) {
760
        const H10: u64 = u64::from_ne_bytes(*b"HTTP/1.0");
761
        const H11: u64 = u64::from_ne_bytes(*b"HTTP/1.1");
762
        // SAFETY: peek_n(8) before ensure within bounds
763
3.38k
        unsafe {
764
3.38k
            bytes.advance(8);
765
3.38k
        }
766
3.38k
        return match u64::from_ne_bytes(eight) {
767
1.03k
            H10 => Ok(Status::Complete(0)),
768
981
            H11 => Ok(Status::Complete(1)),
769
1.37k
            _ => Err(Error::Version),
770
        };
771
434
    }
772
434
773
434
    // else (but not in `else` because of borrow checker)
774
434
775
434
    // If there aren't at least 8 bytes, we still want to detect early
776
434
    // if this is a valid version or not. If it is, we'll return Partial.
777
434
    expect!(bytes.next() == b'H' => Err(Error::Version));
778
337
    expect!(bytes.next() == b'T' => Err(Error::Version));
779
280
    expect!(bytes.next() == b'T' => Err(Error::Version));
780
227
    expect!(bytes.next() == b'P' => Err(Error::Version));
781
172
    expect!(bytes.next() == b'/' => Err(Error::Version));
782
114
    expect!(bytes.next() == b'1' => Err(Error::Version));
783
56
    expect!(bytes.next() == b'.' => Err(Error::Version));
784
7
    Ok(Status::Partial)
785
3.81k
}
786
787
#[inline]
788
#[doc(hidden)]
789
#[allow(missing_docs)]
790
// WARNING: Exported for internal benchmarks, not fit for public consumption
791
2.09k
pub fn parse_method<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
792
    const GET: [u8; 4] = *b"GET ";
793
    const POST: [u8; 4] = *b"POST";
794
2.09k
    match bytes.peek_n::<[u8; 4]>(4) {
795
        Some(GET) => {
796
            // SAFETY: we matched "GET " which has 4 bytes and is ASCII
797
3
            let method = unsafe {
798
3
                bytes.advance(4); // advance cursor past "GET "
799
3
                str::from_utf8_unchecked(bytes.slice_skip(1)) // "GET" without space
800
3
            };
801
3
            Ok(Status::Complete(method))
802
        }
803
        // SAFETY:
804
        // If `bytes.peek_n...` returns a Some([u8; 4]),
805
        // then we are assured that `bytes` contains at least 4 bytes.
806
        // Thus `bytes.len() >= 4`,
807
        // and it is safe to peek at byte 4 with `bytes.peek_ahead(4)`.
808
34
        Some(POST) if unsafe { bytes.peek_ahead(4) } == Some(b' ') => {
809
2
            // SAFETY: we matched "POST " which has 5 bytes
810
2
            let method = unsafe {
811
2
                bytes.advance(5); // advance cursor past "POST "
812
2
                str::from_utf8_unchecked(bytes.slice_skip(1)) // "POST" without space
813
2
            };
814
2
            Ok(Status::Complete(method))
815
        }
816
2.09k
        _ => parse_token(bytes),
817
    }
818
2.09k
}
819
820
/// From [RFC 7230](https://tools.ietf.org/html/rfc7230):
821
///
822
/// > ```notrust
823
/// > reason-phrase  = *( HTAB / SP / VCHAR / obs-text )
824
/// > HTAB           = %x09        ; horizontal tab
825
/// > VCHAR          = %x21-7E     ; visible (printing) characters
826
/// > obs-text       = %x80-FF
827
/// > ```
828
///
829
/// > A.2.  Changes from RFC 2616
830
/// >
831
/// > Non-US-ASCII content in header fields and the reason phrase
832
/// > has been obsoleted and made opaque (the TEXT rule was removed).
833
#[inline]
834
196
fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
835
196
    let mut seen_obs_text = false;
836
    loop {
837
2.52k
        let b = next!(bytes);
838
2.41k
        if b == b'\r' {
839
41
            expect!(bytes.next() == b'\n' => Err(Error::Status));
840
            return Ok(Status::Complete(
841
                // SAFETY: (1) calling bytes.slice_skip(2) is safe, because at least two next! calls
842
                // advance the bytes iterator.
843
                // (2) calling from_utf8_unchecked is safe, because the bytes returned by slice_skip
844
                // were validated to be allowed US-ASCII chars by the other arms of the if/else or
845
                // otherwise `seen_obs_text` is true and an empty string is returned instead.
846
                unsafe {
847
13
                    let bytes = bytes.slice_skip(2);
848
13
                    if !seen_obs_text {
849
                        // all bytes up till `i` must have been HTAB / SP / VCHAR
850
10
                        str::from_utf8_unchecked(bytes)
851
                    } else {
852
                        // obs-text characters were found, so return the fallback empty string
853
3
                        ""
854
                    }
855
                },
856
            ));
857
2.36k
        } else if b == b'\n' {
858
            return Ok(Status::Complete(
859
                // SAFETY: (1) calling bytes.slice_skip(1) is safe, because at least one next! call
860
                // advance the bytes iterator.
861
                // (2) see (2) of safety comment above.
862
                unsafe {
863
21
                    let bytes = bytes.slice_skip(1);
864
21
                    if !seen_obs_text {
865
                        // all bytes up till `i` must have been HTAB / SP / VCHAR
866
14
                        str::from_utf8_unchecked(bytes)
867
                    } else {
868
                        // obs-text characters were found, so return the fallback empty string
869
7
                        ""
870
                    }
871
                },
872
            ));
873
2.34k
        } else if !(b == 0x09 || b == b' ' || (0x21..=0x7E).contains(&b) || b >= 0x80) {
874
18
            return Err(Error::Status);
875
2.33k
        } else if b >= 0x80 {
876
657
            seen_obs_text = true;
877
1.67k
        }
878
    }
879
196
}
880
881
#[inline]
882
2.09k
fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
883
2.09k
    let b = next!(bytes);
884
2.09k
    if !is_method_token(b) {
885
        // First char must be a token char, it can't be a space which would indicate an empty token.
886
46
        return Err(Error::Token);
887
2.04k
    }
888
889
    loop {
890
4.03k
        let b = next!(bytes);
891
3.91k
        if b == b' ' {
892
1.78k
            return Ok(Status::Complete(
893
1.78k
                // SAFETY: all bytes up till `i` must have been `is_method_token` and therefore also utf-8.
894
1.78k
                unsafe { str::from_utf8_unchecked(bytes.slice_skip(1)) },
895
1.78k
            ));
896
2.13k
        } else if !is_method_token(b) {
897
146
            return Err(Error::Token);
898
1.98k
        }
899
    }
900
2.09k
}
901
902
#[inline]
903
#[doc(hidden)]
904
#[allow(missing_docs)]
905
// WARNING: Exported for internal benchmarks, not fit for public consumption
906
1.77k
pub fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
907
1.77k
    let start = bytes.pos();
908
1.77k
    simd::match_uri_vectored(bytes);
909
1.77k
    let end = bytes.pos();
910
1.77k
911
1.77k
    if next!(bytes) == b' ' {
912
        // URI must have at least one char
913
1.69k
        if end == start {
914
2
            return Err(Error::Token);
915
1.69k
        }
916
1.69k
917
1.69k
        // SAFETY: all bytes up till `i` must have been `is_token` and therefore also utf-8.
918
1.69k
        match str::from_utf8(unsafe { bytes.slice_skip(1) }) {
919
1.61k
            Ok(uri) => Ok(Status::Complete(uri)),
920
76
            Err(_) => Err(Error::Token),
921
        }
922
    } else {
923
34
        Err(Error::Token)
924
    }
925
1.77k
}
926
927
#[inline]
928
1.16k
fn parse_code(bytes: &mut Bytes<'_>) -> Result<u16> {
929
1.16k
    let hundreds = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
930
1.11k
    let tens = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
931
1.07k
    let ones = expect!(bytes.next() == b'0'..=b'9' => Err(Error::Status));
932
933
1.03k
    Ok(Status::Complete((hundreds - b'0') as u16 * 100 +
934
1.03k
        (tens - b'0') as u16 * 10 +
935
1.03k
        (ones - b'0') as u16))
936
1.16k
}
937
938
/// Parse a buffer of bytes as headers.
939
///
940
/// The return value, if complete and successful, includes the index of the
941
/// buffer that parsing stopped at, and a sliced reference to the parsed
942
/// headers. The length of the slice will be equal to the number of properly
943
/// parsed headers.
944
///
945
/// # Example
946
///
947
/// ```
948
/// let buf = b"Host: foo.bar\nAccept: */*\n\nblah blah";
949
/// let mut headers = [httparse::EMPTY_HEADER; 4];
950
/// assert_eq!(httparse::parse_headers(buf, &mut headers),
951
///            Ok(httparse::Status::Complete((27, &[
952
///                httparse::Header { name: "Host", value: b"foo.bar" },
953
///                httparse::Header { name: "Accept", value: b"*/*" }
954
///            ][..]))));
955
/// ```
956
383
pub fn parse_headers<'b: 'h, 'h>(
957
383
    src: &'b [u8],
958
383
    mut dst: &'h mut [Header<'b>],
959
383
) -> Result<(usize, &'h [Header<'b>])> {
960
383
    let mut iter = Bytes::new(src);
961
383
    let pos = complete!(parse_headers_iter(&mut dst, &mut iter, &HeaderParserConfig::default()));
962
4
    Ok(Status::Complete((pos, dst)))
963
383
}
964
965
#[inline]
966
383
fn parse_headers_iter<'a>(
967
383
    headers: &mut &mut [Header<'a>],
968
383
    bytes: &mut Bytes<'a>,
969
383
    config: &HeaderParserConfig,
970
383
) -> Result<usize> {
971
383
    parse_headers_iter_uninit(
972
383
        /* SAFETY: see `parse_headers_iter_uninit` guarantees */
973
383
        unsafe { deinit_slice_mut(headers) },
974
383
        bytes,
975
383
        config,
976
383
    )
977
383
}
978
979
383
unsafe fn deinit_slice_mut<'a, 'b, T>(s: &'a mut &'b mut [T]) -> &'a mut &'b mut [MaybeUninit<T>] {
980
383
    let s: *mut &mut [T] = s;
981
383
    let s = s as *mut &mut [MaybeUninit<T>];
982
383
    &mut *s
983
383
}
984
31
unsafe fn assume_init_slice<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] {
985
31
    let s: *mut [MaybeUninit<T>] = s;
986
31
    let s = s as *mut [T];
987
31
    &mut *s
988
31
}
989
990
#[derive(Clone, Debug, Default)]
991
struct HeaderParserConfig {
992
    allow_spaces_after_header_name: bool,
993
    allow_obsolete_multiline_headers: bool,
994
    allow_space_before_first_header_name: bool,
995
    ignore_invalid_headers: bool,
996
}
997
998
/* Function which parsers headers into uninitialized buffer.
999
 *
1000
 * Guarantees that it doesn't write garbage, so casting
1001
 * &mut &mut [Header] -> &mut &mut [MaybeUninit<Header>]
1002
 * is safe here.
1003
 *
1004
 * Also it promises `headers` get shrunk to number of initialized headers,
1005
 * so casting the other way around after calling this function is safe
1006
 */
1007
1.97k
fn parse_headers_iter_uninit<'a>(
1008
1.97k
    headers: &mut &mut [MaybeUninit<Header<'a>>],
1009
1.97k
    bytes: &mut Bytes<'a>,
1010
1.97k
    config: &HeaderParserConfig
1011
1.97k
) -> Result<usize> {
1012
1013
    /* Flow of this function is pretty complex, especially with macros,
1014
     * so this struct makes sure we shrink `headers` to only parsed ones.
1015
     * Comparing to previous code, this only may introduce some additional
1016
     * instructions in case of early return */
1017
    struct ShrinkOnDrop<'r1, 'r2, 'a> {
1018
        headers: &'r1 mut &'r2 mut [MaybeUninit<Header<'a>>],
1019
        num_headers: usize,
1020
    }
1021
1022
    impl Drop for ShrinkOnDrop<'_, '_, '_> {
1023
1.97k
        fn drop(&mut self) {
1024
1.97k
            let headers = mem::take(self.headers);
1025
1.97k
1026
1.97k
            /* SAFETY: num_headers is the number of initialized headers */
1027
1.97k
            let headers = unsafe { headers.get_unchecked_mut(..self.num_headers) };
1028
1.97k
1029
1.97k
            *self.headers = headers;
1030
1.97k
        }
1031
    }
1032
1033
1.97k
    let mut autoshrink = ShrinkOnDrop {
1034
1.97k
        headers,
1035
1.97k
        num_headers: 0,
1036
1.97k
    };
1037
1.97k
    // Track starting pointer to calculate the number of bytes parsed.
1038
1.97k
    let start = bytes.as_ref().as_ptr() as usize;
1039
1.97k
    let mut result = Err(Error::TooManyHeaders);
1040
1.97k
1041
1.97k
    let mut iter = autoshrink.headers.iter_mut();
1042
1043
    macro_rules! maybe_continue_after_obsolete_line_folding {
1044
        ($bytes:ident, $label:lifetime) => {
1045
            if config.allow_obsolete_multiline_headers {
1046
                match $bytes.peek() {
1047
                    None => {
1048
                        // Next byte may be a space, in which case that header
1049
                        // is using obsolete line folding, so we may have more
1050
                        // whitespace to skip after colon.
1051
                        return Ok(Status::Partial);
1052
                    }
1053
                    Some(b' ') | Some(b'\t') => {
1054
                        // The space will be consumed next iteration.
1055
                        continue $label;
1056
                    }
1057
                    _ => {
1058
                        // There is another byte after the end of the line,
1059
                        // but it's not whitespace, so it's probably another
1060
                        // header or the final line return. This header is thus
1061
                        // empty.
1062
                    },
1063
                }
1064
            }
1065
        }
1066
    }
1067
1068
5.13k
    'headers: loop {
1069
5.13k
        // Return the error `$err` if `ignore_invalid_headers_in_responses`
1070
5.13k
        // is false, otherwise find the end of the current line and resume
1071
5.13k
        // parsing on the next one.
1072
5.13k
        macro_rules! handle_invalid_char {
1073
            ($bytes:ident, $b:ident, $err:ident) => {
1074
                if !config.ignore_invalid_headers {
1075
                    return Err(Error::$err);
1076
                }
1077
1078
                let mut b = $b;
1079
1080
                loop {
1081
                    if b == b'\r' {
1082
                        expect!(bytes.next() == b'\n' => Err(Error::$err));
1083
                        break;
1084
                    }
1085
                    if b == b'\n' {
1086
                        break;
1087
                    }
1088
                    if b == b'\0' {
1089
                        return Err(Error::$err);
1090
                    }
1091
                    b = next!($bytes);
1092
                }
1093
1094
                $bytes.slice();
1095
1096
                continue 'headers;
1097
            };
1098
        }
1099
1100
        // a newline here means the head is over!
1101
7.10k
        let b = next!(bytes);
1102
6.53k
        if b == b'\r' {
1103
92
            expect!(bytes.next() == b'\n' => Err(Error::NewLine));
1104
20
            let end = bytes.as_ref().as_ptr() as usize;
1105
20
            result = Ok(Status::Complete(end - start));
1106
20
            break;
1107
6.44k
        }
1108
6.44k
        if b == b'\n' {
1109
15
            let end = bytes.as_ref().as_ptr() as usize;
1110
15
            result = Ok(Status::Complete(end - start));
1111
15
            break;
1112
6.43k
        }
1113
6.43k
        if !is_header_name_token(b) {
1114
72
            if config.allow_space_before_first_header_name
1115
0
                && autoshrink.num_headers == 0
1116
0
                && (b == b' ' || b == b'\t')
1117
            {
1118
                //advance past white space and then try parsing header again
1119
0
                while let Some(peek) = bytes.peek() {
1120
0
                    if peek == b' ' || peek == b'\t' {
1121
0
                        next!(bytes);
1122
                    } else {
1123
0
                        break;
1124
                    }
1125
                }
1126
0
                bytes.slice();
1127
0
                continue 'headers;
1128
            } else {
1129
72
                handle_invalid_char!(bytes, b, HeaderName);
1130
            }
1131
6.35k
        }
1132
1133
        #[allow(clippy::never_loop)]
1134
        // parse header name until colon
1135
5.92k
        let header_name: &str = 'name: loop {
1136
6.35k
            simd::match_header_name_vectored(bytes);
1137
6.35k
            let mut b = next!(bytes);
1138
1139
            // SAFETY: previously bumped by 1 with next! -> always safe.
1140
6.21k
            let bslice = unsafe { bytes.slice_skip(1) };
1141
6.21k
            // SAFETY: previous call to match_header_name_vectored ensured all bytes are valid
1142
6.21k
            // header name chars, and as such also valid utf-8.
1143
6.21k
            let name = unsafe { str::from_utf8_unchecked(bslice) };
1144
6.21k
1145
6.21k
            if b == b':' {
1146
5.92k
                break 'name name;
1147
287
            }
1148
287
1149
287
            if config.allow_spaces_after_header_name {
1150
0
                while b == b' ' || b == b'\t' {
1151
0
                    b = next!(bytes);
1152
1153
0
                    if b == b':' {
1154
0
                        bytes.slice();
1155
0
                        break 'name name;
1156
0
                    }
1157
                }
1158
287
            }
1159
1160
287
            handle_invalid_char!(bytes, b, HeaderName);
1161
        };
1162
1163
        let mut b;
1164
1165
        #[allow(clippy::never_loop)]
1166
5.16k
        let value_slice = 'value: loop {
1167
            // eat white space between colon and value
1168
            'whitespace_after_colon: loop {
1169
9.36k
                b = next!(bytes);
1170
9.21k
                if b == b' ' || b == b'\t' {
1171
3.44k
                    bytes.slice();
1172
3.44k
                    continue 'whitespace_after_colon;
1173
5.77k
                }
1174
5.77k
                if is_header_value_token(b) {
1175
2.28k
                    break 'whitespace_after_colon;
1176
3.49k
                }
1177
3.49k
1178
3.49k
                if b == b'\r' {
1179
397
                    expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
1180
3.10k
                } else if b != b'\n' {
1181
20
                    handle_invalid_char!(bytes, b, HeaderValue);
1182
3.08k
                }
1183
1184
3.41k
                maybe_continue_after_obsolete_line_folding!(bytes, 'whitespace_after_colon);
1185
1186
3.41k
                let whitespace_slice = bytes.slice();
1187
3.41k
1188
3.41k
                // This produces an empty slice that points to the beginning
1189
3.41k
                // of the whitespace.
1190
3.41k
                break 'value &whitespace_slice[0..0];
1191
            }
1192
1193
            'value_lines: loop {
1194
                // parse value till EOL
1195
1196
2.28k
                simd::match_header_value_vectored(bytes);
1197
2.28k
                let b = next!(bytes);
1198
1199
                //found_ctl
1200
2.03k
                let skip = if b == b'\r' {
1201
498
                    expect!(bytes.next() == b'\n' => Err(Error::HeaderValue));
1202
418
                    2
1203
1.53k
                } else if b == b'\n' {
1204
1.33k
                    1
1205
                } else {
1206
198
                    handle_invalid_char!(bytes, b, HeaderValue);
1207
                };
1208
1209
1.75k
                maybe_continue_after_obsolete_line_folding!(bytes, 'value_lines);
1210
1211
                // SAFETY: having just checked that a newline exists, it's safe to skip it.
1212
                unsafe {
1213
1.75k
                    break 'value bytes.slice_skip(skip);
1214
                }
1215
            }
1216
        };
1217
1218
5.16k
        let uninit_header = match iter.next() {
1219
5.13k
            Some(header) => header,
1220
38
            None => break 'headers
1221
        };
1222
1223
        // trim trailing whitespace in the header
1224
5.13k
        let header_value = if let Some(last_visible) = value_slice
1225
5.13k
            .iter()
1226
5.51k
            .rposition(|b| *b != b' ' && *b != b'\t' && *b != b'\r' && *b != b'\n')
1227
        {
1228
            // There is at least one non-whitespace character.
1229
1.73k
            &value_slice[0..last_visible+1]
1230
        } else {
1231
            // There is no non-whitespace character. This can only happen when value_slice is
1232
            // empty.
1233
3.39k
            value_slice
1234
        };
1235
1236
5.13k
        *uninit_header = MaybeUninit::new(Header {
1237
5.13k
            name: header_name,
1238
5.13k
            value: header_value,
1239
5.13k
        });
1240
5.13k
        autoshrink.num_headers += 1;
1241
    }
1242
1243
73
    result
1244
1.97k
}
1245
1246
/// Parse a buffer of bytes as a chunk size.
1247
///
1248
/// The return value, if complete and successful, includes the index of the
1249
/// buffer that parsing stopped at, and the size of the following chunk.
1250
///
1251
/// # Example
1252
///
1253
/// ```
1254
/// let buf = b"4\r\nRust\r\n0\r\n\r\n";
1255
/// assert_eq!(httparse::parse_chunk_size(buf),
1256
///            Ok(httparse::Status::Complete((3, 4))));
1257
/// ```
1258
183
pub fn parse_chunk_size(buf: &[u8])
1259
183
    -> result::Result<Status<(usize, u64)>, InvalidChunkSize> {
1260
    const RADIX: u64 = 16;
1261
183
    let mut bytes = Bytes::new(buf);
1262
183
    let mut size = 0;
1263
183
    let mut in_chunk_size = true;
1264
183
    let mut in_ext = false;
1265
183
    let mut count = 0;
1266
    loop {
1267
273k
        let b = next!(bytes);
1268
272k
        match b {
1269
271k
            b'0' ..= b'9' if in_chunk_size => {
1270
97
                if count > 15 {
1271
1
                    return Err(InvalidChunkSize);
1272
96
                }
1273
96
                count += 1;
1274
96
                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
1275
                    // actually unreachable!(), because count stops the loop at 15 digits before
1276
                    // we can reach u64::MAX / RADIX == 0xfffffffffffffff, which requires 15 hex
1277
                    // digits. This stops mirai reporting a false alarm regarding the `size *=
1278
                    // RADIX` multiplication below.
1279
0
                    return Err(InvalidChunkSize);
1280
96
                }
1281
96
                size *= RADIX;
1282
96
                size += (b - b'0') as u64;
1283
            },
1284
268k
            b'a' ..= b'f' if in_chunk_size => {
1285
67
                if count > 15 {
1286
1
                    return Err(InvalidChunkSize);
1287
66
                }
1288
66
                count += 1;
1289
66
                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
1290
0
                    return Err(InvalidChunkSize);
1291
66
                }
1292
66
                size *= RADIX;
1293
66
                size += (b + 10 - b'a') as u64;
1294
            }
1295
2.56k
            b'A' ..= b'F' if in_chunk_size => {
1296
101
                if count > 15 {
1297
1
                    return Err(InvalidChunkSize);
1298
100
                }
1299
100
                count += 1;
1300
100
                if cfg!(debug_assertions) && size > (u64::MAX / RADIX) {
1301
0
                    return Err(InvalidChunkSize);
1302
100
                }
1303
100
                size *= RADIX;
1304
100
                size += (b + 10 - b'A') as u64;
1305
            }
1306
            b'\r' => {
1307
18
                match next!(bytes) {
1308
2
                    b'\n' => break,
1309
15
                    _ => return Err(InvalidChunkSize),
1310
                }
1311
            }
1312
            // If we weren't in the extension yet, the ";" signals its start
1313
76
            b';' if !in_ext => {
1314
76
                in_ext = true;
1315
76
                in_chunk_size = false;
1316
76
            }
1317
            // "Linear white space" is ignored between the chunk size and the
1318
            // extension separator token (";") due to the "implied *LWS rule".
1319
646
            b'\t' | b' ' if !in_ext && !in_chunk_size => {}
1320
            // LWS can follow the chunk size, but no more digits can come
1321
21
            b'\t' | b' ' if in_chunk_size => in_chunk_size = false,
1322
            // We allow any arbitrary octet once we are in the extension, since
1323
            // they all get ignored anyway. According to the HTTP spec, valid
1324
            // extensions would have a more strict syntax:
1325
            //     (token ["=" (token | quoted-string)])
1326
            // but we gain nothing by rejecting an otherwise valid chunk size.
1327
272k
            _ if in_ext => {}
1328
            // Finally, if we aren't in the extension and we're reading any
1329
            // other octet, the chunk size line is invalid!
1330
35
            _ => return Err(InvalidChunkSize),
1331
        }
1332
    }
1333
2
    Ok(Status::Complete((bytes.pos(), size)))
1334
183
}
1335
1336
#[cfg(test)]
1337
mod tests {
1338
    use super::{Error, Request, Response, Status, EMPTY_HEADER, parse_chunk_size};
1339
1340
    const NUM_OF_HEADERS: usize = 4;
1341
1342
    macro_rules! req {
1343
        ($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
1344
            req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
1345
        );
1346
        ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
1347
        #[test]
1348
        fn $name() {
1349
            let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1350
            let mut req = Request::new(&mut headers[..]);
1351
            let status = req.parse($buf.as_ref());
1352
            assert_eq!(status, $len);
1353
            closure(req);
1354
1355
            fn closure($arg: Request) {
1356
                $body
1357
            }
1358
        }
1359
        )
1360
    }
1361
1362
    req! {
1363
        test_request_simple,
1364
        b"GET / HTTP/1.1\r\n\r\n",
1365
        |req| {
1366
            assert_eq!(req.method.unwrap(), "GET");
1367
            assert_eq!(req.path.unwrap(), "/");
1368
            assert_eq!(req.version.unwrap(), 1);
1369
            assert_eq!(req.headers.len(), 0);
1370
        }
1371
    }
1372
1373
    req! {
1374
        test_request_simple_with_query_params,
1375
        b"GET /thing?data=a HTTP/1.1\r\n\r\n",
1376
        |req| {
1377
            assert_eq!(req.method.unwrap(), "GET");
1378
            assert_eq!(req.path.unwrap(), "/thing?data=a");
1379
            assert_eq!(req.version.unwrap(), 1);
1380
            assert_eq!(req.headers.len(), 0);
1381
        }
1382
    }
1383
1384
    req! {
1385
        test_request_simple_with_whatwg_query_params,
1386
        b"GET /thing?data=a^ HTTP/1.1\r\n\r\n",
1387
        |req| {
1388
            assert_eq!(req.method.unwrap(), "GET");
1389
            assert_eq!(req.path.unwrap(), "/thing?data=a^");
1390
            assert_eq!(req.version.unwrap(), 1);
1391
            assert_eq!(req.headers.len(), 0);
1392
        }
1393
    }
1394
1395
    req! {
1396
        test_request_headers,
1397
        b"GET / HTTP/1.1\r\nHost: foo.com\r\nCookie: \r\n\r\n",
1398
        |req| {
1399
            assert_eq!(req.method.unwrap(), "GET");
1400
            assert_eq!(req.path.unwrap(), "/");
1401
            assert_eq!(req.version.unwrap(), 1);
1402
            assert_eq!(req.headers.len(), 2);
1403
            assert_eq!(req.headers[0].name, "Host");
1404
            assert_eq!(req.headers[0].value, b"foo.com");
1405
            assert_eq!(req.headers[1].name, "Cookie");
1406
            assert_eq!(req.headers[1].value, b"");
1407
        }
1408
    }
1409
1410
    req! {
1411
        test_request_headers_optional_whitespace,
1412
        b"GET / HTTP/1.1\r\nHost: \tfoo.com\t \r\nCookie: \t \r\n\r\n",
1413
        |req| {
1414
            assert_eq!(req.method.unwrap(), "GET");
1415
            assert_eq!(req.path.unwrap(), "/");
1416
            assert_eq!(req.version.unwrap(), 1);
1417
            assert_eq!(req.headers.len(), 2);
1418
            assert_eq!(req.headers[0].name, "Host");
1419
            assert_eq!(req.headers[0].value, b"foo.com");
1420
            assert_eq!(req.headers[1].name, "Cookie");
1421
            assert_eq!(req.headers[1].value, b"");
1422
        }
1423
    }
1424
1425
    req! {
1426
        // test the scalar parsing
1427
        test_request_header_value_htab_short,
1428
        b"GET / HTTP/1.1\r\nUser-Agent: some\tagent\r\n\r\n",
1429
        |req| {
1430
            assert_eq!(req.method.unwrap(), "GET");
1431
            assert_eq!(req.path.unwrap(), "/");
1432
            assert_eq!(req.version.unwrap(), 1);
1433
            assert_eq!(req.headers.len(), 1);
1434
            assert_eq!(req.headers[0].name, "User-Agent");
1435
            assert_eq!(req.headers[0].value, b"some\tagent");
1436
        }
1437
    }
1438
1439
    req! {
1440
        // test the sse42 parsing
1441
        test_request_header_value_htab_med,
1442
        b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\tagent\r\n\r\n",
1443
        |req| {
1444
            assert_eq!(req.method.unwrap(), "GET");
1445
            assert_eq!(req.path.unwrap(), "/");
1446
            assert_eq!(req.version.unwrap(), 1);
1447
            assert_eq!(req.headers.len(), 1);
1448
            assert_eq!(req.headers[0].name, "User-Agent");
1449
            assert_eq!(req.headers[0].value, b"1234567890some\tagent");
1450
        }
1451
    }
1452
1453
    req! {
1454
        // test the avx2 parsing
1455
        test_request_header_value_htab_long,
1456
        b"GET / HTTP/1.1\r\nUser-Agent: 1234567890some\t1234567890agent1234567890\r\n\r\n",
1457
        |req| {
1458
            assert_eq!(req.method.unwrap(), "GET");
1459
            assert_eq!(req.path.unwrap(), "/");
1460
            assert_eq!(req.version.unwrap(), 1);
1461
            assert_eq!(req.headers.len(), 1);
1462
            assert_eq!(req.headers[0].name, "User-Agent");
1463
            assert_eq!(req.headers[0].value, &b"1234567890some\t1234567890agent1234567890"[..]);
1464
        }
1465
    }
1466
1467
    req! {
1468
        // test the avx2 parsing
1469
        test_request_header_no_space_after_colon,
1470
        b"GET / HTTP/1.1\r\nUser-Agent:omg-no-space1234567890some1234567890agent1234567890\r\n\r\n",
1471
        |req| {
1472
            assert_eq!(req.method.unwrap(), "GET");
1473
            assert_eq!(req.path.unwrap(), "/");
1474
            assert_eq!(req.version.unwrap(), 1);
1475
            assert_eq!(req.headers.len(), 1);
1476
            assert_eq!(req.headers[0].name, "User-Agent");
1477
            assert_eq!(req.headers[0].value, &b"omg-no-space1234567890some1234567890agent1234567890"[..]);
1478
        }
1479
    }
1480
1481
    req! {
1482
        test_request_headers_max,
1483
        b"GET / HTTP/1.1\r\nA: A\r\nB: B\r\nC: C\r\nD: D\r\n\r\n",
1484
        |req| {
1485
            assert_eq!(req.headers.len(), NUM_OF_HEADERS);
1486
        }
1487
    }
1488
1489
    req! {
1490
        test_request_multibyte,
1491
        b"GET / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\n\r\n",
1492
        |req| {
1493
            assert_eq!(req.method.unwrap(), "GET");
1494
            assert_eq!(req.path.unwrap(), "/");
1495
            assert_eq!(req.version.unwrap(), 1);
1496
            assert_eq!(req.headers.len(), 2);
1497
            assert_eq!(req.headers[0].name, "Host");
1498
            assert_eq!(req.headers[0].value, b"foo.com");
1499
            assert_eq!(req.headers[1].name, "User-Agent");
1500
            assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
1501
        }
1502
    }
1503
1504
    // A single byte which is part of a method is not invalid
1505
    req! {
1506
        test_request_one_byte_method,
1507
        b"G", Ok(Status::Partial),
1508
        |_req| {}
1509
    }
1510
1511
    // A subset of a method is a partial method, not invalid
1512
    req! {
1513
        test_request_partial_method,
1514
        b"GE", Ok(Status::Partial),
1515
        |_req| {}
1516
    }
1517
1518
    // A method, without the delimiting space, is a partial request
1519
    req! {
1520
        test_request_method_no_delimiter,
1521
        b"GET", Ok(Status::Partial),
1522
        |_req| {}
1523
    }
1524
1525
    // Regression test: assert that a partial read with just the method and
1526
    // space results in a partial, rather than a token error from uri parsing.
1527
    req! {
1528
        test_request_method_only,
1529
        b"GET ", Ok(Status::Partial),
1530
        |_req| {}
1531
    }
1532
1533
    req! {
1534
        test_request_partial,
1535
        b"GET / HTTP/1.1\r\n\r", Ok(Status::Partial),
1536
        |_req| {}
1537
    }
1538
1539
    req! {
1540
        test_request_partial_version,
1541
        b"GET / HTTP/1.", Ok(Status::Partial),
1542
        |_req| {}
1543
    }
1544
1545
    req! {
1546
        test_request_method_path_no_delimiter,
1547
        b"GET /", Ok(Status::Partial),
1548
        |_req| {}
1549
    }
1550
1551
    req! {
1552
        test_request_method_path_only,
1553
        b"GET / ", Ok(Status::Partial),
1554
        |_req| {}
1555
    }
1556
1557
    req! {
1558
        test_request_partial_parses_headers_as_much_as_it_can,
1559
        b"GET / HTTP/1.1\r\nHost: yolo\r\n",
1560
        Ok(crate::Status::Partial),
1561
        |req| {
1562
            assert_eq!(req.method.unwrap(), "GET");
1563
            assert_eq!(req.path.unwrap(), "/");
1564
            assert_eq!(req.version.unwrap(), 1);
1565
            assert_eq!(req.headers.len(), NUM_OF_HEADERS); // doesn't slice since not Complete
1566
            assert_eq!(req.headers[0].name, "Host");
1567
            assert_eq!(req.headers[0].value, b"yolo");
1568
        }
1569
    }
1570
1571
    req! {
1572
        test_request_newlines,
1573
        b"GET / HTTP/1.1\nHost: foo.bar\n\n",
1574
        |_r| {}
1575
    }
1576
1577
    req! {
1578
        test_request_empty_lines_prefix,
1579
        b"\r\n\r\nGET / HTTP/1.1\r\n\r\n",
1580
        |req| {
1581
            assert_eq!(req.method.unwrap(), "GET");
1582
            assert_eq!(req.path.unwrap(), "/");
1583
            assert_eq!(req.version.unwrap(), 1);
1584
            assert_eq!(req.headers.len(), 0);
1585
        }
1586
    }
1587
1588
    req! {
1589
        test_request_empty_lines_prefix_lf_only,
1590
        b"\n\nGET / HTTP/1.1\n\n",
1591
        |req| {
1592
            assert_eq!(req.method.unwrap(), "GET");
1593
            assert_eq!(req.path.unwrap(), "/");
1594
            assert_eq!(req.version.unwrap(), 1);
1595
            assert_eq!(req.headers.len(), 0);
1596
        }
1597
    }
1598
1599
    req! {
1600
        test_request_path_backslash,
1601
        b"\n\nGET /\\?wayne\\=5 HTTP/1.1\n\n",
1602
        |req| {
1603
            assert_eq!(req.method.unwrap(), "GET");
1604
            assert_eq!(req.path.unwrap(), "/\\?wayne\\=5");
1605
            assert_eq!(req.version.unwrap(), 1);
1606
            assert_eq!(req.headers.len(), 0);
1607
        }
1608
    }
1609
1610
    req! {
1611
        test_request_with_invalid_token_delimiter,
1612
        b"GET\n/ HTTP/1.1\r\nHost: foo.bar\r\n\r\n",
1613
        Err(crate::Error::Token),
1614
        |_r| {}
1615
    }
1616
1617
1618
    req! {
1619
        test_request_with_invalid_but_short_version,
1620
        b"GET / HTTP/1!",
1621
        Err(crate::Error::Version),
1622
        |_r| {}
1623
    }
1624
1625
    req! {
1626
        test_request_with_empty_method,
1627
        b" / HTTP/1.1\r\n\r\n",
1628
        Err(crate::Error::Token),
1629
        |_r| {}
1630
    }
1631
1632
    req! {
1633
        test_request_with_empty_path,
1634
        b"GET  HTTP/1.1\r\n\r\n",
1635
        Err(crate::Error::Token),
1636
        |_r| {}
1637
    }
1638
1639
    req! {
1640
        test_request_with_empty_method_and_path,
1641
        b"  HTTP/1.1\r\n\r\n",
1642
        Err(crate::Error::Token),
1643
        |_r| {}
1644
    }
1645
1646
    macro_rules! res {
1647
        ($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
1648
            res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
1649
        );
1650
        ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
1651
        #[test]
1652
        fn $name() {
1653
            let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1654
            let mut res = Response::new(&mut headers[..]);
1655
            let status = res.parse($buf.as_ref());
1656
            assert_eq!(status, $len);
1657
            closure(res);
1658
1659
            fn closure($arg: Response) {
1660
                $body
1661
            }
1662
        }
1663
        )
1664
    }
1665
1666
    res! {
1667
        test_response_simple,
1668
        b"HTTP/1.1 200 OK\r\n\r\n",
1669
        |res| {
1670
            assert_eq!(res.version.unwrap(), 1);
1671
            assert_eq!(res.code.unwrap(), 200);
1672
            assert_eq!(res.reason.unwrap(), "OK");
1673
        }
1674
    }
1675
1676
    res! {
1677
        test_response_newlines,
1678
        b"HTTP/1.0 403 Forbidden\nServer: foo.bar\n\n",
1679
        |_r| {}
1680
    }
1681
1682
    res! {
1683
        test_response_reason_missing,
1684
        b"HTTP/1.1 200 \r\n\r\n",
1685
        |res| {
1686
            assert_eq!(res.version.unwrap(), 1);
1687
            assert_eq!(res.code.unwrap(), 200);
1688
            assert_eq!(res.reason.unwrap(), "");
1689
        }
1690
    }
1691
1692
    res! {
1693
        test_response_reason_missing_no_space,
1694
        b"HTTP/1.1 200\r\n\r\n",
1695
        |res| {
1696
            assert_eq!(res.version.unwrap(), 1);
1697
            assert_eq!(res.code.unwrap(), 200);
1698
            assert_eq!(res.reason.unwrap(), "");
1699
        }
1700
    }
1701
1702
    res! {
1703
        test_response_reason_missing_no_space_with_headers,
1704
        b"HTTP/1.1 200\r\nFoo: bar\r\n\r\n",
1705
        |res| {
1706
            assert_eq!(res.version.unwrap(), 1);
1707
            assert_eq!(res.code.unwrap(), 200);
1708
            assert_eq!(res.reason.unwrap(), "");
1709
            assert_eq!(res.headers.len(), 1);
1710
            assert_eq!(res.headers[0].name, "Foo");
1711
            assert_eq!(res.headers[0].value, b"bar");
1712
        }
1713
    }
1714
1715
    res! {
1716
        test_response_reason_with_space_and_tab,
1717
        b"HTTP/1.1 101 Switching Protocols\t\r\n\r\n",
1718
        |res| {
1719
            assert_eq!(res.version.unwrap(), 1);
1720
            assert_eq!(res.code.unwrap(), 101);
1721
            assert_eq!(res.reason.unwrap(), "Switching Protocols\t");
1722
        }
1723
    }
1724
1725
    static RESPONSE_REASON_WITH_OBS_TEXT_BYTE: &[u8] = b"HTTP/1.1 200 X\xFFZ\r\n\r\n";
1726
    res! {
1727
        test_response_reason_with_obsolete_text_byte,
1728
        RESPONSE_REASON_WITH_OBS_TEXT_BYTE,
1729
        |res| {
1730
            assert_eq!(res.version.unwrap(), 1);
1731
            assert_eq!(res.code.unwrap(), 200);
1732
            // Empty string fallback in case of obs-text
1733
            assert_eq!(res.reason.unwrap(), "");
1734
        }
1735
    }
1736
1737
    res! {
1738
        test_response_reason_with_nul_byte,
1739
        b"HTTP/1.1 200 \x00\r\n\r\n",
1740
        Err(crate::Error::Status),
1741
        |_res| {}
1742
    }
1743
1744
    res! {
1745
        test_response_version_missing_space,
1746
        b"HTTP/1.1",
1747
        Ok(Status::Partial),
1748
        |_res| {}
1749
    }
1750
1751
    res! {
1752
        test_response_code_missing_space,
1753
        b"HTTP/1.1 200",
1754
        Ok(Status::Partial),
1755
        |_res| {}
1756
    }
1757
1758
    res! {
1759
        test_response_partial_parses_headers_as_much_as_it_can,
1760
        b"HTTP/1.1 200 OK\r\nServer: yolo\r\n",
1761
        Ok(crate::Status::Partial),
1762
        |res| {
1763
            assert_eq!(res.version.unwrap(), 1);
1764
            assert_eq!(res.code.unwrap(), 200);
1765
            assert_eq!(res.reason.unwrap(), "OK");
1766
            assert_eq!(res.headers.len(), NUM_OF_HEADERS); // doesn't slice since not Complete
1767
            assert_eq!(res.headers[0].name, "Server");
1768
            assert_eq!(res.headers[0].value, b"yolo");
1769
        }
1770
    }
1771
1772
    res! {
1773
        test_response_empty_lines_prefix_lf_only,
1774
        b"\n\nHTTP/1.1 200 OK\n\n",
1775
        |_res| {}
1776
    }
1777
1778
    res! {
1779
        test_response_no_cr,
1780
        b"HTTP/1.0 200\nContent-type: text/html\n\n",
1781
        |res| {
1782
            assert_eq!(res.version.unwrap(), 0);
1783
            assert_eq!(res.code.unwrap(), 200);
1784
            assert_eq!(res.reason.unwrap(), "");
1785
            assert_eq!(res.headers.len(), 1);
1786
            assert_eq!(res.headers[0].name, "Content-type");
1787
            assert_eq!(res.headers[0].value, b"text/html");
1788
        }
1789
    }
1790
1791
    /// Check all subset permutations of a partial request line with no headers
1792
    #[test]
1793
    fn partial_permutations() {
1794
        let req_str = "GET / HTTP/1.1\r\n\r\n";
1795
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
1796
        let mut req = Request::new(&mut headers[..]);
1797
        for i in 0..req_str.len() {
1798
            let status = req.parse(req_str[..i].as_bytes());
1799
            assert_eq!(
1800
                status,
1801
                Ok(Status::Partial),
1802
                "partial request line should return partial. \
1803
                 Portion which failed: '{seg}' (below {i})",
1804
                seg = &req_str[..i]
1805
            );
1806
        }
1807
    }
1808
1809
    static RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &[u8] =
1810
        b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials : true\r\nBread: baguette\r\n\r\n";
1811
1812
    #[test]
1813
    fn test_forbid_response_with_whitespace_between_header_name_and_colon() {
1814
        let mut headers = [EMPTY_HEADER; 2];
1815
        let mut response = Response::new(&mut headers[..]);
1816
        let result = response.parse(RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1817
1818
        assert_eq!(result, Err(crate::Error::HeaderName));
1819
    }
1820
1821
    #[test]
1822
    fn test_allow_response_with_whitespace_between_header_name_and_colon() {
1823
        let mut headers = [EMPTY_HEADER; 2];
1824
        let mut response = Response::new(&mut headers[..]);
1825
        let result = crate::ParserConfig::default()
1826
            .allow_spaces_after_header_name_in_responses(true)
1827
            .parse_response(&mut response, RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1828
1829
        assert_eq!(result, Ok(Status::Complete(77)));
1830
        assert_eq!(response.version.unwrap(), 1);
1831
        assert_eq!(response.code.unwrap(), 200);
1832
        assert_eq!(response.reason.unwrap(), "OK");
1833
        assert_eq!(response.headers.len(), 2);
1834
        assert_eq!(response.headers[0].name, "Access-Control-Allow-Credentials");
1835
        assert_eq!(response.headers[0].value, &b"true"[..]);
1836
        assert_eq!(response.headers[1].name, "Bread");
1837
        assert_eq!(response.headers[1].value, &b"baguette"[..]);
1838
    }
1839
1840
    #[test]
1841
    fn test_ignore_header_line_with_whitespaces_after_header_name_in_response() {
1842
        let mut headers = [EMPTY_HEADER; 2];
1843
        let mut response = Response::new(&mut headers[..]);
1844
        let result = crate::ParserConfig::default()
1845
            .ignore_invalid_headers_in_responses(true)
1846
            .parse_response(&mut response, RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1847
1848
        assert_eq!(result, Ok(Status::Complete(77)));
1849
        assert_eq!(response.version.unwrap(), 1);
1850
        assert_eq!(response.code.unwrap(), 200);
1851
        assert_eq!(response.reason.unwrap(), "OK");
1852
        assert_eq!(response.headers.len(), 1);
1853
        assert_eq!(response.headers[0].name, "Bread");
1854
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
1855
    }
1856
1857
    static REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &[u8] =
1858
        b"GET / HTTP/1.1\r\nHost : localhost\r\n\r\n";
1859
1860
    #[test]
1861
    fn test_forbid_request_with_whitespace_between_header_name_and_colon() {
1862
        let mut headers = [EMPTY_HEADER; 1];
1863
        let mut request = Request::new(&mut headers[..]);
1864
        let result = request.parse(REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1865
1866
        assert_eq!(result, Err(crate::Error::HeaderName));
1867
    }
1868
1869
    #[test]
1870
    fn test_ignore_header_line_with_whitespaces_after_header_name_in_request() {
1871
        let mut headers = [EMPTY_HEADER; 2];
1872
        let mut request = Request::new(&mut headers[..]);
1873
        let result = crate::ParserConfig::default()
1874
            .ignore_invalid_headers_in_requests(true)
1875
            .parse_request(&mut request, REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1876
1877
        assert_eq!(result, Ok(Status::Complete(36)));
1878
    }
1879
1880
    static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START: &[u8] =
1881
        b"HTTP/1.1 200 OK\r\nLine-Folded-Header: \r\n   \r\n hello there\r\n\r\n";
1882
1883
    #[test]
1884
    fn test_forbid_response_with_obsolete_line_folding_at_start() {
1885
        let mut headers = [EMPTY_HEADER; 1];
1886
        let mut response = Response::new(&mut headers[..]);
1887
        let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START);
1888
1889
        assert_eq!(result, Err(crate::Error::HeaderName));
1890
    }
1891
1892
    #[test]
1893
    fn test_allow_response_with_obsolete_line_folding_at_start() {
1894
        let mut headers = [EMPTY_HEADER; 1];
1895
        let mut response = Response::new(&mut headers[..]);
1896
        let result = crate::ParserConfig::default()
1897
            .allow_obsolete_multiline_headers_in_responses(true)
1898
            .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START);
1899
1900
        assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START.len())));
1901
        assert_eq!(response.version.unwrap(), 1);
1902
        assert_eq!(response.code.unwrap(), 200);
1903
        assert_eq!(response.reason.unwrap(), "OK");
1904
        assert_eq!(response.headers.len(), 1);
1905
        assert_eq!(response.headers[0].name, "Line-Folded-Header");
1906
        assert_eq!(response.headers[0].value, &b"hello there"[..]);
1907
    }
1908
1909
    static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END: &[u8] =
1910
        b"HTTP/1.1 200 OK\r\nLine-Folded-Header: hello there\r\n   \r\n \r\n\r\n";
1911
1912
    #[test]
1913
    fn test_forbid_response_with_obsolete_line_folding_at_end() {
1914
        let mut headers = [EMPTY_HEADER; 1];
1915
        let mut response = Response::new(&mut headers[..]);
1916
        let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END);
1917
1918
        assert_eq!(result, Err(crate::Error::HeaderName));
1919
    }
1920
1921
    #[test]
1922
    fn test_allow_response_with_obsolete_line_folding_at_end() {
1923
        let mut headers = [EMPTY_HEADER; 1];
1924
        let mut response = Response::new(&mut headers[..]);
1925
        let result = crate::ParserConfig::default()
1926
            .allow_obsolete_multiline_headers_in_responses(true)
1927
            .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END);
1928
1929
        assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_END.len())));
1930
        assert_eq!(response.version.unwrap(), 1);
1931
        assert_eq!(response.code.unwrap(), 200);
1932
        assert_eq!(response.reason.unwrap(), "OK");
1933
        assert_eq!(response.headers.len(), 1);
1934
        assert_eq!(response.headers[0].name, "Line-Folded-Header");
1935
        assert_eq!(response.headers[0].value, &b"hello there"[..]);
1936
    }
1937
1938
    static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE: &[u8] =
1939
        b"HTTP/1.1 200 OK\r\nLine-Folded-Header: hello  \r\n \r\n there\r\n\r\n";
1940
1941
    #[test]
1942
    fn test_forbid_response_with_obsolete_line_folding_in_middle() {
1943
        let mut headers = [EMPTY_HEADER; 1];
1944
        let mut response = Response::new(&mut headers[..]);
1945
        let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE);
1946
1947
        assert_eq!(result, Err(crate::Error::HeaderName));
1948
    }
1949
1950
    #[test]
1951
    fn test_allow_response_with_obsolete_line_folding_in_middle() {
1952
        let mut headers = [EMPTY_HEADER; 1];
1953
        let mut response = Response::new(&mut headers[..]);
1954
        let result = crate::ParserConfig::default()
1955
            .allow_obsolete_multiline_headers_in_responses(true)
1956
            .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE);
1957
1958
        assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_MIDDLE.len())));
1959
        assert_eq!(response.version.unwrap(), 1);
1960
        assert_eq!(response.code.unwrap(), 200);
1961
        assert_eq!(response.reason.unwrap(), "OK");
1962
        assert_eq!(response.headers.len(), 1);
1963
        assert_eq!(response.headers[0].name, "Line-Folded-Header");
1964
        assert_eq!(response.headers[0].value, &b"hello  \r\n \r\n there"[..]);
1965
    }
1966
1967
    static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER: &[u8] =
1968
        b"HTTP/1.1 200 OK\r\nLine-Folded-Header:   \r\n \r\n \r\n\r\n";
1969
1970
    #[test]
1971
    fn test_forbid_response_with_obsolete_line_folding_in_empty_header() {
1972
        let mut headers = [EMPTY_HEADER; 1];
1973
        let mut response = Response::new(&mut headers[..]);
1974
        let result = response.parse(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER);
1975
1976
        assert_eq!(result, Err(crate::Error::HeaderName));
1977
    }
1978
1979
    #[test]
1980
    fn test_allow_response_with_obsolete_line_folding_in_empty_header() {
1981
        let mut headers = [EMPTY_HEADER; 1];
1982
        let mut response = Response::new(&mut headers[..]);
1983
        let result = crate::ParserConfig::default()
1984
            .allow_obsolete_multiline_headers_in_responses(true)
1985
            .parse_response(&mut response, RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER);
1986
1987
        assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_OBSOLETE_LINE_FOLDING_IN_EMPTY_HEADER.len())));
1988
        assert_eq!(response.version.unwrap(), 1);
1989
        assert_eq!(response.code.unwrap(), 200);
1990
        assert_eq!(response.reason.unwrap(), "OK");
1991
        assert_eq!(response.headers.len(), 1);
1992
        assert_eq!(response.headers[0].name, "Line-Folded-Header");
1993
        assert_eq!(response.headers[0].value, &b""[..]);
1994
    }
1995
1996
    #[test]
1997
    fn test_chunk_size() {
1998
        assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
1999
        assert_eq!(parse_chunk_size(b"12\r\nchunk"), Ok(Status::Complete((4, 18))));
2000
        assert_eq!(parse_chunk_size(b"3086d\r\n"), Ok(Status::Complete((7, 198765))));
2001
        assert_eq!(parse_chunk_size(b"3735AB1;foo bar*\r\n"), Ok(Status::Complete((18, 57891505))));
2002
        assert_eq!(parse_chunk_size(b"3735ab1 ; baz \r\n"), Ok(Status::Complete((16, 57891505))));
2003
        assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial));
2004
        assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial));
2005
        assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(crate::InvalidChunkSize));
2006
        assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(crate::InvalidChunkSize));
2007
        assert_eq!(parse_chunk_size(b"567xf8a\r\n"), Err(crate::InvalidChunkSize));
2008
        assert_eq!(parse_chunk_size(b"ffffffffffffffff\r\n"), Ok(Status::Complete((18, u64::MAX))));
2009
        assert_eq!(parse_chunk_size(b"1ffffffffffffffff\r\n"), Err(crate::InvalidChunkSize));
2010
        assert_eq!(parse_chunk_size(b"Affffffffffffffff\r\n"), Err(crate::InvalidChunkSize));
2011
        assert_eq!(parse_chunk_size(b"fffffffffffffffff\r\n"), Err(crate::InvalidChunkSize));
2012
    }
2013
2014
    static RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS: &[u8] =
2015
        b"HTTP/1.1   200  OK\r\n\r\n";
2016
2017
    #[test]
2018
    fn test_forbid_response_with_multiple_space_delimiters() {
2019
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2020
        let mut response = Response::new(&mut headers[..]);
2021
        let result = response.parse(RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS);
2022
2023
        assert_eq!(result, Err(crate::Error::Status));
2024
    }
2025
2026
    #[test]
2027
    fn test_allow_response_with_multiple_space_delimiters() {
2028
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2029
        let mut response = Response::new(&mut headers[..]);
2030
        let result = crate::ParserConfig::default()
2031
            .allow_multiple_spaces_in_response_status_delimiters(true)
2032
            .parse_response(&mut response, RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS);
2033
2034
        assert_eq!(result, Ok(Status::Complete(RESPONSE_WITH_MULTIPLE_SPACE_DELIMITERS.len())));
2035
        assert_eq!(response.version.unwrap(), 1);
2036
        assert_eq!(response.code.unwrap(), 200);
2037
        assert_eq!(response.reason.unwrap(), "OK");
2038
        assert_eq!(response.headers.len(), 0);
2039
    }
2040
2041
    /// This is technically allowed by the spec, but we only support multiple spaces as an option,
2042
    /// not stray `\r`s.
2043
    static RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS: &[u8] =
2044
        b"HTTP/1.1 200\rOK\r\n\r\n";
2045
2046
    #[test]
2047
    fn test_forbid_response_with_weird_whitespace_delimiters() {
2048
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2049
        let mut response = Response::new(&mut headers[..]);
2050
        let result = response.parse(RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS);
2051
2052
        assert_eq!(result, Err(crate::Error::Status));
2053
    }
2054
2055
    #[test]
2056
    fn test_still_forbid_response_with_weird_whitespace_delimiters() {
2057
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2058
        let mut response = Response::new(&mut headers[..]);
2059
        let result = crate::ParserConfig::default()
2060
            .allow_multiple_spaces_in_response_status_delimiters(true)
2061
            .parse_response(&mut response, RESPONSE_WITH_WEIRD_WHITESPACE_DELIMITERS);
2062
        assert_eq!(result, Err(crate::Error::Status));
2063
    }
2064
2065
    static REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS: &[u8] =
2066
        b"GET  /    HTTP/1.1\r\n\r\n";
2067
2068
    #[test]
2069
    fn test_forbid_request_with_multiple_space_delimiters() {
2070
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2071
        let mut request = Request::new(&mut headers[..]);
2072
        let result = request.parse(REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS);
2073
2074
        assert_eq!(result, Err(crate::Error::Token));
2075
    }
2076
2077
    #[test]
2078
    fn test_allow_request_with_multiple_space_delimiters() {
2079
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2080
        let mut request = Request::new(&mut headers[..]);
2081
        let result = crate::ParserConfig::default()
2082
            .allow_multiple_spaces_in_request_line_delimiters(true)
2083
            .parse_request(&mut request, REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS);
2084
2085
        assert_eq!(result, Ok(Status::Complete(REQUEST_WITH_MULTIPLE_SPACE_DELIMITERS.len())));
2086
        assert_eq!(request.method.unwrap(), "GET");
2087
        assert_eq!(request.path.unwrap(), "/");
2088
        assert_eq!(request.version.unwrap(), 1);
2089
        assert_eq!(request.headers.len(), 0);
2090
    }
2091
2092
    /// This is technically allowed by the spec, but we only support multiple spaces as an option,
2093
    /// not stray `\r`s.
2094
    static REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS: &[u8] =
2095
        b"GET\r/\rHTTP/1.1\r\n\r\n";
2096
2097
    #[test]
2098
    fn test_forbid_request_with_weird_whitespace_delimiters() {
2099
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2100
        let mut request = Request::new(&mut headers[..]);
2101
        let result = request.parse(REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS);
2102
2103
        assert_eq!(result, Err(crate::Error::Token));
2104
    }
2105
2106
    #[test]
2107
    fn test_still_forbid_request_with_weird_whitespace_delimiters() {
2108
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2109
        let mut request = Request::new(&mut headers[..]);
2110
        let result = crate::ParserConfig::default()
2111
            .allow_multiple_spaces_in_request_line_delimiters(true)
2112
            .parse_request(&mut request, REQUEST_WITH_WEIRD_WHITESPACE_DELIMITERS);
2113
        assert_eq!(result, Err(crate::Error::Token));
2114
    }
2115
2116
    static REQUEST_WITH_MULTIPLE_SPACES_AND_BAD_PATH: &[u8] = b"GET   /foo ohno HTTP/1.1\r\n\r\n";
2117
2118
    #[test]
2119
    fn test_request_with_multiple_spaces_and_bad_path() {
2120
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2121
        let mut request = Request::new(&mut headers[..]);
2122
        let result = crate::ParserConfig::default()
2123
            .allow_multiple_spaces_in_request_line_delimiters(true)
2124
            .parse_request(&mut request, REQUEST_WITH_MULTIPLE_SPACES_AND_BAD_PATH);
2125
        assert_eq!(result, Err(crate::Error::Version));
2126
    }
2127
2128
    // This test ensure there is an error when there is a DEL character in the path
2129
    // since we allow all char from 0x21 code except DEL, this test ensure that DEL
2130
    // is not allowed in the path
2131
    static REQUEST_WITH_DEL_IN_PATH: &[u8] = b"GET   /foo\x7Fohno HTTP/1.1\r\n\r\n";
2132
2133
    #[test]
2134
    fn test_request_with_del_in_path() {
2135
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2136
        let mut request = Request::new(&mut headers[..]);
2137
        let result = crate::ParserConfig::default()
2138
            .allow_multiple_spaces_in_request_line_delimiters(true)
2139
            .parse_request(&mut request, crate::tests::REQUEST_WITH_DEL_IN_PATH);
2140
        assert_eq!(result, Err(crate::Error::Token));
2141
    }
2142
2143
    #[test]
2144
    #[cfg_attr(miri, ignore)] // Miri is too slow for this test
2145
    fn test_all_utf8_char_in_paths() {
2146
        // two code points
2147
        for i in 128..256 {
2148
            for j in 128..256 {
2149
                let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2150
                let mut request = Request::new(&mut headers[..]);
2151
                let bytes = [i as u8, j as u8];
2152
2153
                match core::str::from_utf8(&bytes) {
2154
                    Ok(s) => {
2155
                        let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
2156
                        let result = crate::ParserConfig::default()
2157
                            .allow_multiple_spaces_in_request_line_delimiters(true)
2158
                            .parse_request(&mut request, first_line.as_bytes());
2159
2160
                        assert_eq!(result, Ok(Status::Complete(20)), "failed for utf8 char i: {}, j: {}", i, j);
2161
                    },
2162
                    Err(_) => {
2163
                        let mut first_line = b"GET /".to_vec();
2164
                        first_line.extend(&bytes);
2165
                        first_line.extend(b" HTTP/1.1\r\n\r\n");
2166
2167
                        let result = crate::ParserConfig::default()
2168
                            .allow_multiple_spaces_in_request_line_delimiters(true)
2169
                            .parse_request(&mut request, first_line.as_slice());
2170
2171
                        assert_eq!(result, Err(crate::Error::Token), "failed for utf8 char i: {}, j: {}", i, j);
2172
                    },
2173
                };
2174
2175
                // three code points starting from 0xe0
2176
                if i < 0xe0 {
2177
                    continue;
2178
                }
2179
2180
                for k in 128..256 {
2181
                    let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2182
                    let mut request = Request::new(&mut headers[..]);
2183
                    let bytes = [i as u8, j as u8, k as u8];
2184
2185
                    match core::str::from_utf8(&bytes) {
2186
                        Ok(s) => {
2187
                            let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
2188
                            let result = crate::ParserConfig::default()
2189
                                .allow_multiple_spaces_in_request_line_delimiters(true)
2190
                                .parse_request(&mut request, first_line.as_bytes());
2191
2192
                            assert_eq!(result, Ok(Status::Complete(21)), "failed for utf8 char i: {}, j: {}, k: {}", i, j, k);
2193
                        },
2194
                        Err(_) => {
2195
                            let mut first_line = b"GET /".to_vec();
2196
                            first_line.extend(&bytes);
2197
                            first_line.extend(b" HTTP/1.1\r\n\r\n");
2198
2199
                            let result = crate::ParserConfig::default()
2200
                                .allow_multiple_spaces_in_request_line_delimiters(true)
2201
                                .parse_request(&mut request, first_line.as_slice());
2202
2203
                            assert_eq!(result, Err(crate::Error::Token), "failed for utf8 char i: {}, j: {}, k: {}", i, j, k);
2204
                        },
2205
                    };
2206
2207
                    // four code points starting from 0xf0
2208
                    if i < 0xf0 {
2209
                        continue;
2210
                    }
2211
2212
                    for l in 128..256 {
2213
                        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2214
                        let mut request = Request::new(&mut headers[..]);
2215
                        let bytes = [i as u8, j as u8, k as u8, l as u8];
2216
2217
                        match core::str::from_utf8(&bytes) {
2218
                            Ok(s) => {
2219
                                let first_line = format!("GET /{} HTTP/1.1\r\n\r\n", s);
2220
                                let result = crate::ParserConfig::default()
2221
                                    .allow_multiple_spaces_in_request_line_delimiters(true)
2222
                                    .parse_request(&mut request, first_line.as_bytes());
2223
2224
                                assert_eq!(result, Ok(Status::Complete(22)), "failed for utf8 char i: {}, j: {}, k: {}, l: {}", i, j, k, l);
2225
                            },
2226
                            Err(_) => {
2227
                                let mut first_line = b"GET /".to_vec();
2228
                                first_line.extend(&bytes);
2229
                                first_line.extend(b" HTTP/1.1\r\n\r\n");
2230
2231
                                let result = crate::ParserConfig::default()
2232
                                    .allow_multiple_spaces_in_request_line_delimiters(true)
2233
                                    .parse_request(&mut request, first_line.as_slice());
2234
2235
                                assert_eq!(result, Err(crate::Error::Token), "failed for utf8 char i: {}, j: {}, k: {}, l: {}", i, j, k, l);
2236
                            },
2237
                        };
2238
                    }
2239
                }
2240
            }
2241
        }
2242
    }
2243
2244
    static RESPONSE_WITH_SPACES_IN_CODE: &[u8] = b"HTTP/1.1 99 200 OK\r\n\r\n";
2245
2246
    #[test]
2247
    fn test_response_with_spaces_in_code() {
2248
        let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
2249
        let mut response = Response::new(&mut headers[..]);
2250
        let result = crate::ParserConfig::default()
2251
            .allow_multiple_spaces_in_response_status_delimiters(true)
2252
            .parse_response(&mut response, RESPONSE_WITH_SPACES_IN_CODE);
2253
        assert_eq!(result, Err(crate::Error::Status));
2254
    }
2255
2256
    #[test]
2257
    fn test_response_with_empty_header_name() {
2258
        const RESPONSE: &[u8] =
2259
            b"HTTP/1.1 200 OK\r\n: hello\r\nBread: baguette\r\n\r\n";
2260
2261
        let mut headers = [EMPTY_HEADER; 2];
2262
        let mut response = Response::new(&mut headers[..]);
2263
2264
        let result = crate::ParserConfig::default()
2265
            .allow_spaces_after_header_name_in_responses(true)
2266
            .parse_response(&mut response, RESPONSE);
2267
        assert_eq!(result, Err(crate::Error::HeaderName));
2268
2269
        let result = crate::ParserConfig::default()
2270
            .ignore_invalid_headers_in_responses(true)
2271
            .parse_response(&mut response, RESPONSE);
2272
        assert_eq!(result, Ok(Status::Complete(45)));
2273
2274
        assert_eq!(response.version.unwrap(), 1);
2275
        assert_eq!(response.code.unwrap(), 200);
2276
        assert_eq!(response.reason.unwrap(), "OK");
2277
        assert_eq!(response.headers.len(), 1);
2278
        assert_eq!(response.headers[0].name, "Bread");
2279
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
2280
    }
2281
2282
    #[test]
2283
    fn test_request_with_empty_header_name() {
2284
        const RESPONSE: &[u8] =
2285
            b"GET / HTTP/1.1\r\n: hello\r\nBread: baguette\r\n\r\n";
2286
2287
        let mut headers = [EMPTY_HEADER; 2];
2288
        let mut request = Request::new(&mut headers[..]);
2289
2290
        let result = crate::ParserConfig::default()
2291
            .parse_request(&mut request, RESPONSE);
2292
        assert_eq!(result, Err(crate::Error::HeaderName));
2293
2294
        let result = crate::ParserConfig::default()
2295
            .ignore_invalid_headers_in_requests(true)
2296
            .parse_request(&mut request, RESPONSE);
2297
        assert_eq!(result, Ok(Status::Complete(44)));
2298
    }
2299
2300
    #[test]
2301
    fn test_request_with_whitespace_between_header_name_and_colon() {
2302
        const REQUEST: &[u8] =
2303
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials  : true\r\nBread: baguette\r\n\r\n";
2304
2305
        let mut headers = [EMPTY_HEADER; 2];
2306
        let mut request = Request::new(&mut headers[..]);
2307
2308
        let result = crate::ParserConfig::default()
2309
            .allow_spaces_after_header_name_in_responses(true)
2310
            .parse_request(&mut request, REQUEST);
2311
        assert_eq!(result, Err(crate::Error::HeaderName));
2312
2313
        let result = crate::ParserConfig::default()
2314
2315
            .ignore_invalid_headers_in_responses(true)
2316
            .parse_request(&mut request, REQUEST);
2317
        assert_eq!(result, Err(crate::Error::HeaderName));
2318
    }
2319
2320
    #[test]
2321
    fn test_response_with_invalid_char_between_header_name_and_colon() {
2322
        const RESPONSE: &[u8] =
2323
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\xFF  : true\r\nBread: baguette\r\n\r\n";
2324
2325
        let mut headers = [EMPTY_HEADER; 2];
2326
        let mut response = Response::new(&mut headers[..]);
2327
2328
        let result = crate::ParserConfig::default()
2329
            .allow_spaces_after_header_name_in_responses(true)
2330
            .parse_response(&mut response, RESPONSE);
2331
        assert_eq!(result, Err(crate::Error::HeaderName));
2332
2333
        let result = crate::ParserConfig::default()
2334
            .ignore_invalid_headers_in_responses(true)
2335
            .parse_response(&mut response, RESPONSE);
2336
2337
        assert_eq!(result, Ok(Status::Complete(79)));
2338
        assert_eq!(response.version.unwrap(), 1);
2339
        assert_eq!(response.code.unwrap(), 200);
2340
        assert_eq!(response.reason.unwrap(), "OK");
2341
        assert_eq!(response.headers.len(), 1);
2342
        assert_eq!(response.headers[0].name, "Bread");
2343
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
2344
    }
2345
2346
    #[test]
2347
    fn test_request_with_invalid_char_between_header_name_and_colon() {
2348
        const REQUEST: &[u8] =
2349
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials\xFF  : true\r\nBread: baguette\r\n\r\n";
2350
2351
        let mut headers = [EMPTY_HEADER; 2];
2352
        let mut request = Request::new(&mut headers[..]);
2353
2354
        let result = crate::ParserConfig::default()
2355
            .parse_request(&mut request, REQUEST);
2356
        assert_eq!(result, Err(crate::Error::HeaderName));
2357
2358
        let result = crate::ParserConfig::default()
2359
            .ignore_invalid_headers_in_requests(true)
2360
            .parse_request(&mut request, REQUEST);
2361
        assert_eq!(result, Ok(Status::Complete(78)));
2362
    }
2363
2364
    #[test]
2365
    fn test_ignore_header_line_with_missing_colon_in_response() {
2366
        const RESPONSE: &[u8] =
2367
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n";
2368
2369
        let mut headers = [EMPTY_HEADER; 2];
2370
        let mut response = Response::new(&mut headers[..]);
2371
2372
        let result = crate::ParserConfig::default()
2373
            .parse_response(&mut response, RESPONSE);
2374
        assert_eq!(result, Err(crate::Error::HeaderName));
2375
2376
        let result = crate::ParserConfig::default()
2377
            .ignore_invalid_headers_in_responses(true)
2378
            .parse_response(&mut response, RESPONSE);
2379
        assert_eq!(result, Ok(Status::Complete(70)));
2380
2381
        assert_eq!(response.version.unwrap(), 1);
2382
        assert_eq!(response.code.unwrap(), 200);
2383
        assert_eq!(response.reason.unwrap(), "OK");
2384
        assert_eq!(response.headers.len(), 1);
2385
        assert_eq!(response.headers[0].name, "Bread");
2386
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
2387
    }
2388
2389
    #[test]
2390
    fn test_ignore_header_line_with_missing_colon_in_request() {
2391
        const REQUEST: &[u8] =
2392
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n";
2393
2394
        let mut headers = [EMPTY_HEADER; 2];
2395
        let mut request = Request::new(&mut headers[..]);
2396
2397
        let result = crate::ParserConfig::default()
2398
            .parse_request(&mut request, REQUEST);
2399
        assert_eq!(result, Err(crate::Error::HeaderName));
2400
2401
        let result = crate::ParserConfig::default()
2402
            .ignore_invalid_headers_in_requests(true)
2403
            .parse_request(&mut request, REQUEST);
2404
        assert_eq!(result, Ok(Status::Complete(69)));
2405
    }
2406
2407
    #[test]
2408
    fn test_response_header_with_missing_colon_with_folding() {
2409
        const RESPONSE: &[u8] =
2410
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials   \r\n hello\r\nBread: baguette\r\n\r\n";
2411
2412
        let mut headers = [EMPTY_HEADER; 2];
2413
        let mut response = Response::new(&mut headers[..]);
2414
2415
        let result = crate::ParserConfig::default()
2416
            .allow_obsolete_multiline_headers_in_responses(true)
2417
            .allow_spaces_after_header_name_in_responses(true)
2418
            .parse_response(&mut response, RESPONSE);
2419
        assert_eq!(result, Err(crate::Error::HeaderName));
2420
2421
        let result = crate::ParserConfig::default()
2422
            .ignore_invalid_headers_in_responses(true)
2423
            .parse_response(&mut response, RESPONSE);
2424
        assert_eq!(result, Ok(Status::Complete(81)));
2425
2426
        assert_eq!(response.version.unwrap(), 1);
2427
        assert_eq!(response.code.unwrap(), 200);
2428
        assert_eq!(response.reason.unwrap(), "OK");
2429
        assert_eq!(response.headers.len(), 1);
2430
        assert_eq!(response.headers[0].name, "Bread");
2431
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
2432
    }
2433
2434
    #[test]
2435
    fn test_request_header_with_missing_colon_with_folding() {
2436
        const REQUEST: &[u8] =
2437
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials   \r\n hello\r\nBread: baguette\r\n\r\n";
2438
2439
        let mut headers = [EMPTY_HEADER; 2];
2440
        let mut request = Request::new(&mut headers[..]);
2441
2442
        let result = crate::ParserConfig::default()
2443
            .parse_request(&mut request, REQUEST);
2444
        assert_eq!(result, Err(crate::Error::HeaderName));
2445
2446
        let result = crate::ParserConfig::default()
2447
            .ignore_invalid_headers_in_requests(true)
2448
            .parse_request(&mut request, REQUEST);
2449
        assert_eq!(result, Ok(Status::Complete(80)));
2450
    }
2451
2452
    #[test]
2453
    fn test_response_header_with_nul_in_header_name() {
2454
        const RESPONSE: &[u8] =
2455
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n";
2456
2457
        let mut headers = [EMPTY_HEADER; 2];
2458
        let mut response = Response::new(&mut headers[..]);
2459
2460
        let result = crate::ParserConfig::default()
2461
            .parse_response(&mut response, RESPONSE);
2462
        assert_eq!(result, Err(crate::Error::HeaderName));
2463
2464
        let result = crate::ParserConfig::default()
2465
            .ignore_invalid_headers_in_responses(true)
2466
            .parse_response(&mut response, RESPONSE);
2467
        assert_eq!(result, Err(crate::Error::HeaderName));
2468
    }
2469
2470
    #[test]
2471
    fn test_request_header_with_nul_in_header_name() {
2472
        const REQUEST: &[u8] =
2473
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Cred\0entials: hello\r\nBread: baguette\r\n\r\n";
2474
2475
        let mut headers = [EMPTY_HEADER; 2];
2476
        let mut request = Request::new(&mut headers[..]);
2477
2478
        let result = crate::ParserConfig::default()
2479
            .parse_request(&mut request, REQUEST);
2480
        assert_eq!(result, Err(crate::Error::HeaderName));
2481
2482
        let result = crate::ParserConfig::default()
2483
            .ignore_invalid_headers_in_requests(true)
2484
            .parse_request(&mut request, REQUEST);
2485
        assert_eq!(result, Err(crate::Error::HeaderName));
2486
    }
2487
2488
    #[test]
2489
    fn test_header_with_cr_in_header_name() {
2490
        const RESPONSE: &[u8] =
2491
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n";
2492
2493
        let mut headers = [EMPTY_HEADER; 2];
2494
        let mut response = Response::new(&mut headers[..]);
2495
2496
        let result = crate::ParserConfig::default()
2497
            .parse_response(&mut response, RESPONSE);
2498
        assert_eq!(result, Err(crate::Error::HeaderName));
2499
2500
        let result = crate::ParserConfig::default()
2501
            .ignore_invalid_headers_in_responses(true)
2502
            .parse_response(&mut response, RESPONSE);
2503
        assert_eq!(result, Err(crate::Error::HeaderName));
2504
2505
        const REQUEST: &[u8] =
2506
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Cred\rentials: hello\r\nBread: baguette\r\n\r\n";
2507
2508
        let mut headers = [EMPTY_HEADER; 2];
2509
        let mut request = Request::new(&mut headers[..]);
2510
2511
        let result = crate::ParserConfig::default()
2512
            .parse_request(&mut request, REQUEST);
2513
        assert_eq!(result, Err(crate::Error::HeaderName));
2514
2515
        let result = crate::ParserConfig::default()
2516
            .ignore_invalid_headers_in_requests(true)
2517
            .parse_request(&mut request, REQUEST);
2518
        assert_eq!(result, Err(crate::Error::HeaderName));
2519
    }
2520
2521
    #[test]
2522
    fn test_header_with_nul_in_whitespace_before_colon() {
2523
        const RESPONSE: &[u8] =
2524
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials   \0: hello\r\nBread: baguette\r\n\r\n";
2525
2526
        let mut headers = [EMPTY_HEADER; 2];
2527
        let mut response = Response::new(&mut headers[..]);
2528
2529
        let result = crate::ParserConfig::default()
2530
            .allow_spaces_after_header_name_in_responses(true)
2531
            .parse_response(&mut response, RESPONSE);
2532
        assert_eq!(result, Err(crate::Error::HeaderName));
2533
2534
        let result = crate::ParserConfig::default()
2535
            .allow_spaces_after_header_name_in_responses(true)
2536
            .ignore_invalid_headers_in_responses(true)
2537
            .parse_response(&mut response, RESPONSE);
2538
        assert_eq!(result, Err(crate::Error::HeaderName));
2539
2540
        const REQUEST: &[u8] =
2541
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials   \0: hello\r\nBread: baguette\r\n\r\n";
2542
2543
        let mut headers = [EMPTY_HEADER; 2];
2544
        let mut request = Request::new(&mut headers[..]);
2545
2546
        let result = crate::ParserConfig::default()
2547
            .ignore_invalid_headers_in_requests(true)
2548
            .parse_request(&mut request, REQUEST);
2549
        assert_eq!(result, Err(crate::Error::HeaderName));
2550
    }
2551
2552
    #[test]
2553
    fn test_header_with_nul_in_value() {
2554
        const RESPONSE: &[u8] =
2555
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n";
2556
2557
        let mut headers = [EMPTY_HEADER; 2];
2558
        let mut response = Response::new(&mut headers[..]);
2559
2560
        let result = crate::ParserConfig::default()
2561
            .parse_response(&mut response, RESPONSE);
2562
        assert_eq!(result, Err(crate::Error::HeaderValue));
2563
2564
        let result = crate::ParserConfig::default()
2565
            .ignore_invalid_headers_in_responses(true)
2566
            .parse_response(&mut response, RESPONSE);
2567
        assert_eq!(result, Err(crate::Error::HeaderValue));
2568
2569
        const REQUEST: &[u8] =
2570
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\0o\r\nBread: baguette\r\n\r\n";
2571
2572
        let mut headers = [EMPTY_HEADER; 2];
2573
        let mut request = Request::new(&mut headers[..]);
2574
2575
        let result = crate::ParserConfig::default()
2576
            .parse_request(&mut request, REQUEST);
2577
        assert_eq!(result, Err(crate::Error::HeaderValue));
2578
2579
        let result = crate::ParserConfig::default()
2580
            .ignore_invalid_headers_in_requests(true)
2581
            .parse_request(&mut request, REQUEST);
2582
        assert_eq!(result, Err(crate::Error::HeaderValue));
2583
    }
2584
2585
    #[test]
2586
    fn test_header_with_invalid_char_in_value() {
2587
        const RESPONSE: &[u8] =
2588
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n";
2589
2590
        let mut headers = [EMPTY_HEADER; 2];
2591
        let mut response = Response::new(&mut headers[..]);
2592
2593
        let result = crate::ParserConfig::default()
2594
            .parse_response(&mut response, RESPONSE);
2595
        assert_eq!(result, Err(crate::Error::HeaderValue));
2596
2597
        let result = crate::ParserConfig::default()
2598
            .ignore_invalid_headers_in_responses(true)
2599
            .parse_response(&mut response, RESPONSE);
2600
        assert_eq!(result, Ok(Status::Complete(78)));
2601
2602
        assert_eq!(response.version.unwrap(), 1);
2603
        assert_eq!(response.code.unwrap(), 200);
2604
        assert_eq!(response.reason.unwrap(), "OK");
2605
        assert_eq!(response.headers.len(), 1);
2606
        assert_eq!(response.headers[0].name, "Bread");
2607
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
2608
2609
        const REQUEST: &[u8] =
2610
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\x01o\r\nBread: baguette\r\n\r\n";
2611
2612
        let mut headers = [EMPTY_HEADER; 2];
2613
        let mut request = Request::new(&mut headers[..]);
2614
2615
        let result = crate::ParserConfig::default()
2616
            .parse_request(&mut request, REQUEST);
2617
        assert_eq!(result, Err(crate::Error::HeaderValue));
2618
2619
        let result = crate::ParserConfig::default()
2620
            .ignore_invalid_headers_in_requests(true)
2621
            .parse_request(&mut request, REQUEST);
2622
        assert_eq!(result, Ok(Status::Complete(77)));
2623
2624
        assert_eq!(request.version.unwrap(), 1);
2625
        assert_eq!(request.method.unwrap(), "GET");
2626
        assert_eq!(request.path.unwrap(), "/");
2627
        assert_eq!(request.headers.len(), 1);
2628
        assert_eq!(request.headers[0].name, "Bread");
2629
        assert_eq!(request.headers[0].value, &b"baguette"[..]);
2630
    }
2631
2632
    #[test]
2633
    fn test_header_with_invalid_char_in_value_with_folding() {
2634
        const RESPONSE: &[u8] =
2635
            b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials: hell\x01o  \n world!\r\nBread: baguette\r\n\r\n";
2636
2637
        let mut headers = [EMPTY_HEADER; 2];
2638
        let mut response = Response::new(&mut headers[..]);
2639
2640
        let result = crate::ParserConfig::default()
2641
            .parse_response(&mut response, RESPONSE);
2642
        assert_eq!(result, Err(crate::Error::HeaderValue));
2643
2644
        let result = crate::ParserConfig::default()
2645
            .ignore_invalid_headers_in_responses(true)
2646
            .parse_response(&mut response, RESPONSE);
2647
        assert_eq!(result, Ok(Status::Complete(88)));
2648
2649
        assert_eq!(response.version.unwrap(), 1);
2650
        assert_eq!(response.code.unwrap(), 200);
2651
        assert_eq!(response.reason.unwrap(), "OK");
2652
        assert_eq!(response.headers.len(), 1);
2653
        assert_eq!(response.headers[0].name, "Bread");
2654
        assert_eq!(response.headers[0].value, &b"baguette"[..]);
2655
2656
        const REQUEST: &[u8] =
2657
            b"GET / HTTP/1.1\r\nAccess-Control-Allow-Credentials: hell\x01o  \n world!\r\nBread: baguette\r\n\r\n";
2658
2659
        let mut headers = [EMPTY_HEADER; 2];
2660
        let mut request = Request::new(&mut headers[..]);
2661
2662
        let result = crate::ParserConfig::default()
2663
            .parse_request(&mut request, REQUEST);
2664
        assert_eq!(result, Err(crate::Error::HeaderValue));
2665
2666
        let result = crate::ParserConfig::default()
2667
            .ignore_invalid_headers_in_requests(true)
2668
            .parse_request(&mut request, REQUEST);
2669
        assert_eq!(result, Ok(Status::Complete(87)));
2670
2671
        assert_eq!(request.version.unwrap(), 1);
2672
        assert_eq!(request.method.unwrap(), "GET");
2673
        assert_eq!(request.path.unwrap(), "/");
2674
        assert_eq!(request.headers.len(), 1);
2675
        assert_eq!(request.headers[0].name, "Bread");
2676
        assert_eq!(request.headers[0].value, &b"baguette"[..]);
2677
    }
2678
2679
    #[test]
2680
    fn test_method_within_buffer() {
2681
        const REQUEST: &[u8] = b"GET / HTTP/1.1\r\n\r\n";
2682
2683
        let mut headers = [EMPTY_HEADER; 0];
2684
        let mut request = Request::new(&mut headers[..]);
2685
2686
        crate::ParserConfig::default()
2687
            .parse_request(&mut request, REQUEST)
2688
            .unwrap();
2689
2690
        // SAFETY: will not wrap
2691
        let buf_end = unsafe { REQUEST.as_ptr().add(REQUEST.len()) };
2692
        // Check that the method str is within the buffer
2693
        let method = request.method.unwrap();
2694
        assert!(REQUEST.as_ptr() <= method.as_ptr());
2695
        assert!(method.as_ptr() <= buf_end);
2696
    }
2697
2698
     static RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER: &[u8] =
2699
        b"HTTP/1.1 200 OK\r\n Space-Before-Header: hello there\r\n\r\n";
2700
2701
    #[test]
2702
    fn test_forbid_response_with_space_before_first_header() {
2703
        let mut headers = [EMPTY_HEADER; 1];
2704
        let mut response = Response::new(&mut headers[..]);
2705
        let result = response.parse(RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER);
2706
2707
        assert_eq!(result, Err(crate::Error::HeaderName));
2708
    }
2709
2710
    #[test]
2711
    fn test_allow_response_response_with_space_before_first_header() {
2712
        let mut headers = [EMPTY_HEADER; 1];
2713
        let mut response = Response::new(&mut headers[..]);
2714
        let result = crate::ParserConfig::default()
2715
            .allow_space_before_first_header_name(true)
2716
            .parse_response(&mut response, RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER);
2717
2718
        assert_eq!(
2719
            result,
2720
            Ok(Status::Complete(
2721
                RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER.len()
2722
            ))
2723
        );
2724
        assert_eq!(response.version.unwrap(), 1);
2725
        assert_eq!(response.code.unwrap(), 200);
2726
        assert_eq!(response.reason.unwrap(), "OK");
2727
        assert_eq!(response.headers.len(), 1);
2728
        assert_eq!(response.headers[0].name, "Space-Before-Header");
2729
        assert_eq!(response.headers[0].value, &b"hello there"[..]);
2730
    }
2731
2732
    #[test]
2733
    fn test_no_space_after_colon() {
2734
        let mut headers = [EMPTY_HEADER; 1];
2735
        let mut response = Response::new(&mut headers[..]);
2736
        let result = crate::ParserConfig::default()
2737
            .parse_response(&mut response, b"HTTP/1.1 200 OK\r\nfoo:bar\r\n\r\n");
2738
2739
        assert_eq!(result, Ok(Status::Complete(28)));
2740
        assert_eq!(response.version.unwrap(), 1);
2741
        assert_eq!(response.code.unwrap(), 200);
2742
        assert_eq!(response.reason.unwrap(), "OK");
2743
        assert_eq!(response.headers.len(), 1);
2744
        assert_eq!(response.headers[0].name, "foo");
2745
        assert_eq!(response.headers[0].value, &b"bar"[..]);
2746
    }
2747
2748
    #[test]
2749
    fn test_request_with_leading_space() {
2750
        let mut headers = [EMPTY_HEADER; 1];
2751
        let mut request = Request::new(&mut headers[..]);
2752
        let result = crate::ParserConfig::default()
2753
            .parse_request(&mut request, b" GET / HTTP/1.1\r\nfoo:bar\r\n\r\n");
2754
2755
        assert_eq!(result, Err(Error::Token));
2756
    }
2757
2758
    #[test]
2759
    fn test_request_with_invalid_method() {
2760
        let mut headers = [EMPTY_HEADER; 1];
2761
        let mut request = Request::new(&mut headers[..]);
2762
        let result = crate::ParserConfig::default()
2763
            .parse_request(&mut request, b"P()ST / HTTP/1.1\r\nfoo:bar\r\n\r\n");
2764
2765
        assert_eq!(result, Err(Error::Token));
2766
    }
2767
2768
    #[test]
2769
    fn test_utf8_in_path_ok() {
2770
        let mut headers = [EMPTY_HEADER; 1];
2771
        let mut request = Request::new(&mut headers[..]);
2772
2773
        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");
2774
2775
        assert_eq!(result, Ok(Status::Complete(67)));
2776
        assert_eq!(request.version.unwrap(), 1);
2777
        assert_eq!(request.method.unwrap(), "GET");
2778
        assert_eq!(request.path.unwrap(), "/test?post=I’msorryIforkedyou");
2779
        assert_eq!(request.headers.len(), 1);
2780
        assert_eq!(request.headers[0].name, "Host");
2781
        assert_eq!(request.headers[0].value, &b"example.org"[..]);
2782
    }
2783
2784
    #[test]
2785
    fn test_bad_utf8_in_path() {
2786
        let mut headers = [EMPTY_HEADER; 1];
2787
        let mut request = Request::new(&mut headers[..]);
2788
2789
        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");
2790
2791
        assert_eq!(result, Err(crate::Error::Token));
2792
    }
2793
}