@@ -90,9 +90,32 @@ static URI_MAP: [bool; 256] = byte_map![
90
90
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
91
91
] ;
92
92
93
+ static URI_NON_COMPLIANT_MAP : [ bool ; 256 ] = byte_map ! [
94
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
95
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
96
+ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
97
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
98
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
99
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
100
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
101
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 ,
102
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
103
+ 1 , 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 , 1 , 1 , 1 , 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 , 1 , 1 , 1 , 1 , 1 ,
107
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
108
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
109
+ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ,
110
+ ] ;
111
+
93
112
#[ inline]
94
- pub ( crate ) fn is_uri_token ( b : u8 ) -> bool {
95
- URI_MAP [ b as usize ]
113
+ pub ( crate ) fn is_uri_token ( b : u8 , allow_non_compliant : bool ) -> bool {
114
+ if allow_non_compliant {
115
+ URI_NON_COMPLIANT_MAP [ b as usize ]
116
+ } else {
117
+ URI_MAP [ b as usize ]
118
+ }
96
119
}
97
120
98
121
static HEADER_NAME_MAP : [ bool ; 256 ] = byte_map ! [
@@ -260,6 +283,7 @@ pub struct ParserConfig {
260
283
allow_multiple_spaces_in_request_line_delimiters : bool ,
261
284
allow_multiple_spaces_in_response_status_delimiters : bool ,
262
285
allow_space_before_first_header_name : bool ,
286
+ allow_rfc3986_non_compliant_path : bool ,
263
287
ignore_invalid_headers_in_responses : bool ,
264
288
ignore_invalid_headers_in_requests : bool ,
265
289
}
@@ -539,7 +563,7 @@ impl<'h, 'b> Request<'h, 'b> {
539
563
if config. allow_multiple_spaces_in_request_line_delimiters {
540
564
complete ! ( skip_spaces( & mut bytes) ) ;
541
565
}
542
- self . path = Some ( complete ! ( parse_uri( & mut bytes) ) ) ;
566
+ self . path = Some ( complete ! ( parse_uri( & mut bytes, config . allow_rfc3986_non_compliant_path ) ) ) ;
543
567
if config. allow_multiple_spaces_in_request_line_delimiters {
544
568
complete ! ( skip_spaces( & mut bytes) ) ;
545
569
}
@@ -952,9 +976,9 @@ fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
952
976
#[ doc( hidden) ]
953
977
#[ allow( missing_docs) ]
954
978
// WARNING: Exported for internal benchmarks, not fit for public consumption
955
- pub fn parse_uri < ' a > ( bytes : & mut Bytes < ' a > ) -> Result < & ' a str > {
979
+ pub fn parse_uri < ' a > ( bytes : & mut Bytes < ' a > , allow_non_compliant : bool ) -> Result < & ' a str > {
956
980
let start = bytes. pos ( ) ;
957
- simd:: match_uri_vectored ( bytes) ;
981
+ simd:: match_uri_vectored ( bytes, allow_non_compliant ) ;
958
982
let end = bytes. pos ( ) ;
959
983
960
984
if next ! ( bytes) == b' ' {
@@ -2676,4 +2700,32 @@ mod tests {
2676
2700
assert_eq ! ( response. headers[ 0 ] . name, "foo" ) ;
2677
2701
assert_eq ! ( response. headers[ 0 ] . value, & b"bar" [ ..] ) ;
2678
2702
}
2703
+
2704
+ #[ test]
2705
+ fn test_rfc3986_non_compliant_path_ko ( ) {
2706
+ let mut headers = [ EMPTY_HEADER ; 1 ] ;
2707
+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2708
+
2709
+ let result = crate :: ParserConfig :: default ( ) . parse_request ( & mut request, b"GET /test?post=I\xE2 \x80 \x99 msorryIforkedyou HTTP/1.1\r \n Host: example.org\r \n \r \n " ) ;
2710
+
2711
+ assert_eq ! ( result, Err ( crate :: Error :: Token ) ) ;
2712
+ }
2713
+
2714
+ #[ test]
2715
+ fn test_rfc3986_non_compliant_path_ok ( ) {
2716
+ let mut headers = [ EMPTY_HEADER ; 1 ] ;
2717
+ let mut request = Request :: new ( & mut headers[ ..] ) ;
2718
+ let mut config = crate :: ParserConfig :: default ( ) ;
2719
+ config. allow_rfc3986_non_compliant_path = true ;
2720
+
2721
+ let result = config. parse_request ( & mut request, b"GET /test?post=I\xE2 \x80 \x99 msorryIforkedyou HTTP/1.1\r \n Host: example.org\r \n \r \n " ) ;
2722
+
2723
+ assert_eq ! ( result, Ok ( Status :: Complete ( 67 ) ) ) ;
2724
+ assert_eq ! ( request. version. unwrap( ) , 1 ) ;
2725
+ assert_eq ! ( request. method. unwrap( ) , "GET" ) ;
2726
+ assert_eq ! ( request. path. unwrap( ) , "/test?post=I’msorryIforkedyou" ) ;
2727
+ assert_eq ! ( request. headers. len( ) , 1 ) ;
2728
+ assert_eq ! ( request. headers[ 0 ] . name, "Host" ) ;
2729
+ assert_eq ! ( request. headers[ 0 ] . value, & b"example.org" [ ..] ) ;
2730
+ }
2679
2731
}
0 commit comments