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