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