@@ -260,6 +260,7 @@ pub struct ParserConfig {
260
260
allow_multiple_spaces_in_request_line_delimiters : bool ,
261
261
allow_multiple_spaces_in_response_status_delimiters : bool ,
262
262
ignore_invalid_headers_in_responses : bool ,
263
+ ignore_invalid_headers_in_requests : bool ,
263
264
}
264
265
265
266
impl ParserConfig {
@@ -412,6 +413,15 @@ impl ParserConfig {
412
413
self
413
414
}
414
415
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
+
415
425
/// Parses a response with the given config.
416
426
pub fn parse_response < ' buf > (
417
427
& self ,
@@ -506,7 +516,11 @@ impl<'h, 'b> Request<'h, 'b> {
506
516
let headers_len = complete ! ( parse_headers_iter_uninit(
507
517
& mut headers,
508
518
& 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
+ } ,
510
524
) ) ;
511
525
/* SAFETY: see `parse_headers_iter_uninit` guarantees */
512
526
self . headers = unsafe { assume_init_slice ( headers) } ;
@@ -699,7 +713,11 @@ impl<'h, 'b> Response<'h, 'b> {
699
713
let headers_len = complete ! ( parse_headers_iter_uninit(
700
714
& mut headers,
701
715
& 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
+ }
703
721
) ) ;
704
722
/* SAFETY: see `parse_headers_iter_uninit` guarantees */
705
723
self . headers = unsafe { assume_init_slice ( headers) } ;
@@ -950,15 +968,15 @@ pub fn parse_headers<'b: 'h, 'h>(
950
968
mut dst : & ' h mut [ Header < ' b > ] ,
951
969
) -> Result < ( usize , & ' h [ Header < ' b > ] ) > {
952
970
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 ( ) ) ) ;
954
972
Ok ( Status :: Complete ( ( pos, dst) ) )
955
973
}
956
974
957
975
#[ inline]
958
976
fn parse_headers_iter < ' a > (
959
977
headers : & mut & mut [ Header < ' a > ] ,
960
978
bytes : & mut Bytes < ' a > ,
961
- config : & ParserConfig ,
979
+ config : & HeaderParserConfig ,
962
980
) -> Result < usize > {
963
981
parse_headers_iter_uninit (
964
982
/* SAFETY: see `parse_headers_iter_uninit` guarantees */
@@ -979,6 +997,13 @@ unsafe fn assume_init_slice<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] {
979
997
& mut * s
980
998
}
981
999
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
+
982
1007
/* Function which parsers headers into uninitialized buffer.
983
1008
*
984
1009
* 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] {
991
1016
fn parse_headers_iter_uninit < ' a > (
992
1017
headers : & mut & mut [ MaybeUninit < Header < ' a > > ] ,
993
1018
bytes : & mut Bytes < ' a > ,
994
- config : & ParserConfig ,
1019
+ config : & HeaderParserConfig
995
1020
) -> Result < usize > {
996
1021
997
1022
/* Flow of this function is pretty complex, especially with macros,
@@ -1026,7 +1051,7 @@ fn parse_headers_iter_uninit<'a>(
1026
1051
1027
1052
macro_rules! maybe_continue_after_obsolete_line_folding {
1028
1053
( $bytes: ident, $label: lifetime) => {
1029
- if config. allow_obsolete_multiline_headers_in_responses {
1054
+ if config. allow_obsolete_multiline_headers {
1030
1055
match $bytes. peek( ) {
1031
1056
None => {
1032
1057
// Next byte may be a space, in which case that header
@@ -1055,7 +1080,7 @@ fn parse_headers_iter_uninit<'a>(
1055
1080
// parsing on the next one.
1056
1081
macro_rules! handle_invalid_char {
1057
1082
( $bytes: ident, $b: ident, $err: ident) => {
1058
- if !config. ignore_invalid_headers_in_responses {
1083
+ if !config. ignore_invalid_headers {
1059
1084
return Err ( Error :: $err) ;
1060
1085
}
1061
1086
@@ -1114,7 +1139,7 @@ fn parse_headers_iter_uninit<'a>(
1114
1139
break ' name name;
1115
1140
}
1116
1141
1117
- if config. allow_spaces_after_header_name_in_responses {
1142
+ if config. allow_spaces_after_header_name {
1118
1143
while b == b' ' || b == b'\t' {
1119
1144
b = next ! ( bytes) ;
1120
1145
@@ -1733,7 +1758,7 @@ mod tests {
1733
1758
}
1734
1759
1735
1760
#[ 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 ( ) {
1737
1762
let mut headers = [ EMPTY_HEADER ; 2 ] ;
1738
1763
let mut response = Response :: new ( & mut headers[ ..] ) ;
1739
1764
let result = crate :: ParserConfig :: default ( )
@@ -1761,6 +1786,17 @@ mod tests {
1761
1786
assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
1762
1787
}
1763
1788
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
+
1764
1800
static RESPONSE_WITH_OBSOLETE_LINE_FOLDING_AT_START : & [ u8 ] =
1765
1801
b"HTTP/1.1 200 OK\r \n Line-Folded-Header: \r \n \r \n hello there\r \n \r \n " ;
1766
1802
@@ -2047,6 +2083,24 @@ mod tests {
2047
2083
assert_eq ! ( response. headers[ 0 ] . value, & b"baguette" [ ..] ) ;
2048
2084
}
2049
2085
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
+
2050
2104
#[ test]
2051
2105
fn test_request_with_whitespace_between_header_name_and_colon ( ) {
2052
2106
const REQUEST : & [ u8 ] =
@@ -2094,7 +2148,25 @@ mod tests {
2094
2148
}
2095
2149
2096
2150
#[ 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 ( ) {
2098
2170
const RESPONSE : & [ u8 ] =
2099
2171
b"HTTP/1.1 200 OK\r \n Access-Control-Allow-Credentials\r \n Bread: baguette\r \n \r \n " ;
2100
2172
@@ -2119,7 +2191,25 @@ mod tests {
2119
2191
}
2120
2192
2121
2193
#[ 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 ( ) {
2123
2213
const RESPONSE : & [ u8 ] =
2124
2214
b"HTTP/1.1 200 OK\r \n Access-Control-Allow-Credentials \r \n hello\r \n Bread: baguette\r \n \r \n " ;
2125
2215
@@ -2146,7 +2236,25 @@ mod tests {
2146
2236
}
2147
2237
2148
2238
#[ 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 ( ) {
2150
2258
const RESPONSE : & [ u8 ] =
2151
2259
b"HTTP/1.1 200 OK\r \n Access-Control-Allow-Cred\0 entials: hello\r \n Bread: baguette\r \n \r \n " ;
2152
2260
@@ -2163,6 +2271,24 @@ mod tests {
2163
2271
assert_eq ! ( result, Err ( crate :: Error :: HeaderName ) ) ;
2164
2272
}
2165
2273
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
+
2166
2292
#[ test]
2167
2293
fn test_header_with_cr_in_header_name ( ) {
2168
2294
const RESPONSE : & [ u8 ] =
@@ -2179,6 +2305,21 @@ mod tests {
2179
2305
. ignore_invalid_headers_in_responses ( true )
2180
2306
. parse_response ( & mut response, RESPONSE ) ;
2181
2307
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 ) ) ;
2182
2323
}
2183
2324
2184
2325
#[ test]
@@ -2199,6 +2340,17 @@ mod tests {
2199
2340
. ignore_invalid_headers_in_responses ( true )
2200
2341
. parse_response ( & mut response, RESPONSE ) ;
2201
2342
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 ) ) ;
2202
2354
}
2203
2355
2204
2356
#[ test]
@@ -2217,6 +2369,21 @@ mod tests {
2217
2369
. ignore_invalid_headers_in_responses ( true )
2218
2370
. parse_response ( & mut response, RESPONSE ) ;
2219
2371
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 ) ) ;
2220
2387
}
2221
2388
2222
2389
#[ test]
@@ -2242,6 +2409,28 @@ mod tests {
2242
2409
assert_eq ! ( response. headers. len( ) , 1 ) ;
2243
2410
assert_eq ! ( response. headers[ 0 ] . name, "Bread" ) ;
2244
2411
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" [ ..] ) ;
2245
2434
}
2246
2435
2247
2436
#[ test]
@@ -2267,6 +2456,28 @@ mod tests {
2267
2456
assert_eq ! ( response. headers. len( ) , 1 ) ;
2268
2457
assert_eq ! ( response. headers[ 0 ] . name, "Bread" ) ;
2269
2458
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" [ ..] ) ;
2270
2481
}
2271
2482
2272
2483
#[ test]
0 commit comments