@@ -260,6 +260,7 @@ pub struct ParserConfig {
260260 allow_multiple_spaces_in_request_line_delimiters : bool ,
261261 allow_multiple_spaces_in_response_status_delimiters : bool ,
262262 ignore_invalid_headers_in_responses : bool ,
263+ ignore_invalid_headers_in_requests : bool ,
263264}
264265
265266impl ParserConfig {
@@ -412,6 +413,15 @@ impl ParserConfig {
412413 self
413414 }
414415
416+ /// Sets whether invalid header lines should be silently ignored in requests.
417+ pub fn ignore_invalid_headers_in_requests (
418+ & mut self ,
419+ value : bool ,
420+ ) -> & mut Self {
421+ self . ignore_invalid_headers_in_requests = value;
422+ self
423+ }
424+
415425 /// Parses a response with the given config.
416426 pub fn parse_response < ' buf > (
417427 & self ,
@@ -506,7 +516,11 @@ impl<'h, 'b> Request<'h, 'b> {
506516 let headers_len = complete ! ( parse_headers_iter_uninit(
507517 & mut headers,
508518 & mut bytes,
509- & ParserConfig :: default ( ) ,
519+ & HeaderParserConfig {
520+ allow_spaces_after_header_name: false ,
521+ allow_obsolete_multiline_headers: false ,
522+ ignore_invalid_headers: config. ignore_invalid_headers_in_requests
523+ } ,
510524 ) ) ;
511525 /* SAFETY: see `parse_headers_iter_uninit` guarantees */
512526 self . headers = unsafe { assume_init_slice ( headers) } ;
@@ -699,7 +713,11 @@ impl<'h, 'b> Response<'h, 'b> {
699713 let headers_len = complete ! ( parse_headers_iter_uninit(
700714 & mut headers,
701715 & mut bytes,
702- config
716+ & HeaderParserConfig {
717+ allow_spaces_after_header_name: config. allow_spaces_after_header_name_in_responses,
718+ allow_obsolete_multiline_headers: config. allow_obsolete_multiline_headers_in_responses,
719+ ignore_invalid_headers: config. ignore_invalid_headers_in_responses
720+ }
703721 ) ) ;
704722 /* SAFETY: see `parse_headers_iter_uninit` guarantees */
705723 self . headers = unsafe { assume_init_slice ( headers) } ;
@@ -950,15 +968,15 @@ pub fn parse_headers<'b: 'h, 'h>(
950968 mut dst : & ' h mut [ Header < ' b > ] ,
951969) -> Result < ( usize , & ' h [ Header < ' b > ] ) > {
952970 let mut iter = Bytes :: new ( src) ;
953- let pos = complete ! ( parse_headers_iter( & mut dst, & mut iter, & ParserConfig :: default ( ) ) ) ;
971+ let pos = complete ! ( parse_headers_iter( & mut dst, & mut iter, & HeaderParserConfig :: default ( ) ) ) ;
954972 Ok ( Status :: Complete ( ( pos, dst) ) )
955973}
956974
957975#[ inline]
958976fn parse_headers_iter < ' a > (
959977 headers : & mut & mut [ Header < ' a > ] ,
960978 bytes : & mut Bytes < ' a > ,
961- config : & ParserConfig ,
979+ config : & HeaderParserConfig ,
962980) -> Result < usize > {
963981 parse_headers_iter_uninit (
964982 /* SAFETY: see `parse_headers_iter_uninit` guarantees */
@@ -979,6 +997,13 @@ unsafe fn assume_init_slice<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] {
979997 & mut * s
980998}
981999
1000+ #[ derive( Clone , Debug , Default ) ]
1001+ struct HeaderParserConfig {
1002+ allow_spaces_after_header_name : bool ,
1003+ allow_obsolete_multiline_headers : bool ,
1004+ ignore_invalid_headers : bool ,
1005+ }
1006+
9821007/* Function which parsers headers into uninitialized buffer.
9831008 *
9841009 * Guarantees that it doesn't write garbage, so casting
@@ -991,7 +1016,7 @@ unsafe fn assume_init_slice<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] {
9911016fn parse_headers_iter_uninit < ' a > (
9921017 headers : & mut & mut [ MaybeUninit < Header < ' a > > ] ,
9931018 bytes : & mut Bytes < ' a > ,
994- config : & ParserConfig ,
1019+ config : & HeaderParserConfig
9951020) -> Result < usize > {
9961021
9971022 /* Flow of this function is pretty complex, especially with macros,
@@ -1026,7 +1051,7 @@ fn parse_headers_iter_uninit<'a>(
10261051
10271052 macro_rules! maybe_continue_after_obsolete_line_folding {
10281053 ( $bytes: ident, $label: lifetime) => {
1029- if config. allow_obsolete_multiline_headers_in_responses {
1054+ if config. allow_obsolete_multiline_headers {
10301055 match $bytes. peek( ) {
10311056 None => {
10321057 // Next byte may be a space, in which case that header
@@ -1055,7 +1080,7 @@ fn parse_headers_iter_uninit<'a>(
10551080 // parsing on the next one.
10561081 macro_rules! handle_invalid_char {
10571082 ( $bytes: ident, $b: ident, $err: ident) => {
1058- if !config. ignore_invalid_headers_in_responses {
1083+ if !config. ignore_invalid_headers {
10591084 return Err ( Error :: $err) ;
10601085 }
10611086
@@ -1114,7 +1139,7 @@ fn parse_headers_iter_uninit<'a>(
11141139 break ' name name;
11151140 }
11161141
1117- if config. allow_spaces_after_header_name_in_responses {
1142+ if config. allow_spaces_after_header_name {
11181143 while b == b' ' || b == b'\t' {
11191144 b = next ! ( bytes) ;
11201145
@@ -1733,7 +1758,7 @@ mod tests {
17331758 }
17341759
17351760 #[ test]
1736- fn test_ignore_header_line_with_whitespaces_after_header_name ( ) {
1761+ fn test_ignore_header_line_with_whitespaces_after_header_name_in_response ( ) {
17371762 let mut headers = [ EMPTY_HEADER ; 2 ] ;
17381763 let mut response = Response :: new ( & mut headers[ ..] ) ;
17391764 let result = crate :: ParserConfig :: default ( )
@@ -1761,6 +1786,17 @@ mod tests {
17611786 assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
17621787 }
17631788
1789+ #[ test]
1790+ fn test_ignore_header_line_with_whitespaces_after_header_name_in_request ( ) {
1791+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
1792+ let mut request = Request :: new ( & mut headers[ ..] ) ;
1793+ let result = crate :: ParserConfig :: default ( )
1794+ . ignore_invalid_headers_in_requests ( true )
1795+ . parse_request ( & mut request, REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON ) ;
1796+
1797+ assert_eq ! ( result, Ok ( Status :: Complete ( 36 ) ) ) ;
1798+ }
1799+
17641800 static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START : & [ u8 ] =
17651801 b"HTTP/1.1 200 OK\r \n Line-Folded-Header: \r \n \r \n hello there\r \n \r \n " ;
17661802
@@ -2047,6 +2083,24 @@ mod tests {
20472083 assert_eq ! ( response. headers[ 0 ] . value, & b"baguette" [ ..] ) ;
20482084 }
20492085
2086+ #[ test]
2087+ fn test_request_with_empty_header_name ( ) {
2088+ const RESPONSE : & [ u8 ] =
2089+ b"GET / HTTP/1.1\r \n : hello\r \n Bread: baguette\r \n \r \n " ;
2090+
2091+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2092+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2093+
2094+ let result = crate :: ParserConfig :: default ( )
2095+ . parse_request ( & mut request, RESPONSE ) ;
2096+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2097+
2098+ let result = crate :: ParserConfig :: default ( )
2099+ . ignore_invalid_headers_in_requests ( true )
2100+ . parse_request ( & mut request, RESPONSE ) ;
2101+ assert_eq ! ( result, Ok ( Status :: Complete ( 44 ) ) ) ;
2102+ }
2103+
20502104 #[ test]
20512105 fn test_request_with_whitespace_between_header_name_and_colon ( ) {
20522106 const REQUEST : & [ u8 ] =
@@ -2094,7 +2148,25 @@ mod tests {
20942148 }
20952149
20962150 #[ test]
2097- fn test_ignore_header_line_with_missing_colon ( ) {
2151+ fn test_request_with_invalid_char_between_header_name_and_colon ( ) {
2152+ const REQUEST : & [ u8 ] =
2153+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials\xFF : true\r \n Bread: baguette\r \n \r \n " ;
2154+
2155+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2156+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2157+
2158+ let result = crate :: ParserConfig :: default ( )
2159+ . parse_request ( & mut request, REQUEST ) ;
2160+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2161+
2162+ let result = crate :: ParserConfig :: default ( )
2163+ . ignore_invalid_headers_in_requests ( true )
2164+ . parse_request ( & mut request, REQUEST ) ;
2165+ assert_eq ! ( result, Ok ( Status :: Complete ( 78 ) ) ) ;
2166+ }
2167+
2168+ #[ test]
2169+ fn test_ignore_header_line_with_missing_colon_in_response ( ) {
20982170 const RESPONSE : & [ u8 ] =
20992171 b"HTTP/1.1 200 OK\r \n Access-Control-Allow-Credentials\r \n Bread: baguette\r \n \r \n " ;
21002172
@@ -2119,7 +2191,25 @@ mod tests {
21192191 }
21202192
21212193 #[ test]
2122- fn test_header_with_missing_colon_with_folding ( ) {
2194+ fn test_ignore_header_line_with_missing_colon_in_request ( ) {
2195+ const REQUEST : & [ u8 ] =
2196+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials\r \n Bread: baguette\r \n \r \n " ;
2197+
2198+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2199+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2200+
2201+ let result = crate :: ParserConfig :: default ( )
2202+ . parse_request ( & mut request, REQUEST ) ;
2203+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2204+
2205+ let result = crate :: ParserConfig :: default ( )
2206+ . ignore_invalid_headers_in_requests ( true )
2207+ . parse_request ( & mut request, REQUEST ) ;
2208+ assert_eq ! ( result, Ok ( Status :: Complete ( 69 ) ) ) ;
2209+ }
2210+
2211+ #[ test]
2212+ fn test_response_header_with_missing_colon_with_folding ( ) {
21232213 const RESPONSE : & [ u8 ] =
21242214 b"HTTP/1.1 200 OK\r \n Access-Control-Allow-Credentials \r \n hello\r \n Bread: baguette\r \n \r \n " ;
21252215
@@ -2146,7 +2236,25 @@ mod tests {
21462236 }
21472237
21482238 #[ test]
2149- fn test_header_with_nul_in_header_name ( ) {
2239+ fn test_request_header_with_missing_colon_with_folding ( ) {
2240+ const REQUEST : & [ u8 ] =
2241+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials \r \n hello\r \n Bread: baguette\r \n \r \n " ;
2242+
2243+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2244+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2245+
2246+ let result = crate :: ParserConfig :: default ( )
2247+ . parse_request ( & mut request, REQUEST ) ;
2248+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2249+
2250+ let result = crate :: ParserConfig :: default ( )
2251+ . ignore_invalid_headers_in_requests ( true )
2252+ . parse_request ( & mut request, REQUEST ) ;
2253+ assert_eq ! ( result, Ok ( Status :: Complete ( 80 ) ) ) ;
2254+ }
2255+
2256+ #[ test]
2257+ fn test_response_header_with_nul_in_header_name ( ) {
21502258 const RESPONSE : & [ u8 ] =
21512259 b"HTTP/1.1 200 OK\r \n Access-Control-Allow-Cred\0 entials: hello\r \n Bread: baguette\r \n \r \n " ;
21522260
@@ -2163,6 +2271,24 @@ mod tests {
21632271 assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
21642272 }
21652273
2274+ #[ test]
2275+ fn test_request_header_with_nul_in_header_name ( ) {
2276+ const REQUEST : & [ u8 ] =
2277+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Cred\0 entials: hello\r \n Bread: baguette\r \n \r \n " ;
2278+
2279+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2280+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2281+
2282+ let result = crate :: ParserConfig :: default ( )
2283+ . parse_request ( & mut request, REQUEST ) ;
2284+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2285+
2286+ let result = crate :: ParserConfig :: default ( )
2287+ . ignore_invalid_headers_in_requests ( true )
2288+ . parse_request ( & mut request, REQUEST ) ;
2289+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2290+ }
2291+
21662292 #[ test]
21672293 fn test_header_with_cr_in_header_name ( ) {
21682294 const RESPONSE : & [ u8 ] =
@@ -2179,6 +2305,21 @@ mod tests {
21792305 . ignore_invalid_headers_in_responses ( true )
21802306 . parse_response ( & mut response, RESPONSE ) ;
21812307 assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2308+
2309+ const REQUEST : & [ u8 ] =
2310+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Cred\r entials: hello\r \n Bread: baguette\r \n \r \n " ;
2311+
2312+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2313+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2314+
2315+ let result = crate :: ParserConfig :: default ( )
2316+ . parse_request ( & mut request, REQUEST ) ;
2317+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2318+
2319+ let result = crate :: ParserConfig :: default ( )
2320+ . ignore_invalid_headers_in_requests ( true )
2321+ . parse_request ( & mut request, REQUEST ) ;
2322+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
21822323 }
21832324
21842325 #[ test]
@@ -2199,6 +2340,17 @@ mod tests {
21992340 . ignore_invalid_headers_in_responses ( true )
22002341 . parse_response ( & mut response, RESPONSE ) ;
22012342 assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2343+
2344+ const REQUEST : & [ u8 ] =
2345+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials \0 : hello\r \n Bread: baguette\r \n \r \n " ;
2346+
2347+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2348+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2349+
2350+ let result = crate :: ParserConfig :: default ( )
2351+ . ignore_invalid_headers_in_requests ( true )
2352+ . parse_request ( & mut request, REQUEST ) ;
2353+ assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
22022354 }
22032355
22042356 #[ test]
@@ -2217,6 +2369,21 @@ mod tests {
22172369 . ignore_invalid_headers_in_responses ( true )
22182370 . parse_response ( & mut response, RESPONSE ) ;
22192371 assert_eq ! ( result, Err ( crate :: Error :: HeaderValue ) ) ;
2372+
2373+ const REQUEST : & [ u8 ] =
2374+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials: hell\0 o\r \n Bread: baguette\r \n \r \n " ;
2375+
2376+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2377+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2378+
2379+ let result = crate :: ParserConfig :: default ( )
2380+ . parse_request ( & mut request, REQUEST ) ;
2381+ assert_eq ! ( result, Err ( crate :: Error :: HeaderValue ) ) ;
2382+
2383+ let result = crate :: ParserConfig :: default ( )
2384+ . ignore_invalid_headers_in_requests ( true )
2385+ . parse_request ( & mut request, REQUEST ) ;
2386+ assert_eq ! ( result, Err ( crate :: Error :: HeaderValue ) ) ;
22202387 }
22212388
22222389 #[ test]
@@ -2242,6 +2409,28 @@ mod tests {
22422409 assert_eq ! ( response. headers. len( ) , 1 ) ;
22432410 assert_eq ! ( response. headers[ 0 ] . name, "Bread" ) ;
22442411 assert_eq ! ( response. headers[ 0 ] . value, & b"baguette" [ ..] ) ;
2412+
2413+ const REQUEST : & [ u8 ] =
2414+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials: hell\x01 o\r \n Bread: baguette\r \n \r \n " ;
2415+
2416+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2417+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2418+
2419+ let result = crate :: ParserConfig :: default ( )
2420+ . parse_request ( & mut request, REQUEST ) ;
2421+ assert_eq ! ( result, Err ( crate :: Error :: HeaderValue ) ) ;
2422+
2423+ let result = crate :: ParserConfig :: default ( )
2424+ . ignore_invalid_headers_in_requests ( true )
2425+ . parse_request ( & mut request, REQUEST ) ;
2426+ assert_eq ! ( result, Ok ( Status :: Complete ( 77 ) ) ) ;
2427+
2428+ assert_eq ! ( request. version. unwrap( ) , 1 ) ;
2429+ assert_eq ! ( request. method. unwrap( ) , "GET" ) ;
2430+ assert_eq ! ( request. path. unwrap( ) , "/" ) ;
2431+ assert_eq ! ( request. headers. len( ) , 1 ) ;
2432+ assert_eq ! ( request. headers[ 0 ] . name, "Bread" ) ;
2433+ assert_eq ! ( request. headers[ 0 ] . value, & b"baguette" [ ..] ) ;
22452434 }
22462435
22472436 #[ test]
@@ -2267,6 +2456,28 @@ mod tests {
22672456 assert_eq ! ( response. headers. len( ) , 1 ) ;
22682457 assert_eq ! ( response. headers[ 0 ] . name, "Bread" ) ;
22692458 assert_eq ! ( response. headers[ 0 ] . value, & b"baguette" [ ..] ) ;
2459+
2460+ const REQUEST : & [ u8 ] =
2461+ b"GET / HTTP/1.1\r \n Access-Control-Allow-Credentials: hell\x01 o \n world!\r \n Bread: baguette\r \n \r \n " ;
2462+
2463+ let mut headers = [ EMPTY_HEADER ; 2 ] ;
2464+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2465+
2466+ let result = crate :: ParserConfig :: default ( )
2467+ . parse_request ( & mut request, REQUEST ) ;
2468+ assert_eq ! ( result, Err ( crate :: Error :: HeaderValue ) ) ;
2469+
2470+ let result = crate :: ParserConfig :: default ( )
2471+ . ignore_invalid_headers_in_requests ( true )
2472+ . parse_request ( & mut request, REQUEST ) ;
2473+ assert_eq ! ( result, Ok ( Status :: Complete ( 87 ) ) ) ;
2474+
2475+ assert_eq ! ( request. version. unwrap( ) , 1 ) ;
2476+ assert_eq ! ( request. method. unwrap( ) , "GET" ) ;
2477+ assert_eq ! ( request. path. unwrap( ) , "/" ) ;
2478+ assert_eq ! ( request. headers. len( ) , 1 ) ;
2479+ assert_eq ! ( request. headers[ 0 ] . name, "Bread" ) ;
2480+ assert_eq ! ( request. headers[ 0 ] . value, & b"baguette" [ ..] ) ;
22702481 }
22712482
22722483 #[ test]
0 commit comments