@@ -90,9 +90,32 @@ static URI_MAP: [bool; 256] = byte_map![
9090 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
9191] ;
9292
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+
93112#[ 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+ }
96119}
97120
98121static HEADER_NAME_MAP : [ bool ; 256 ] = byte_map ! [
@@ -260,6 +283,7 @@ pub struct ParserConfig {
260283 allow_multiple_spaces_in_request_line_delimiters : bool ,
261284 allow_multiple_spaces_in_response_status_delimiters : bool ,
262285 allow_space_before_first_header_name : bool ,
286+ allow_rfc3986_non_compliant_path : bool ,
263287 ignore_invalid_headers_in_responses : bool ,
264288 ignore_invalid_headers_in_requests : bool ,
265289}
@@ -539,7 +563,7 @@ impl<'h, 'b> Request<'h, 'b> {
539563 if config. allow_multiple_spaces_in_request_line_delimiters {
540564 complete ! ( skip_spaces( & mut bytes) ) ;
541565 }
542- self . path = Some ( complete ! ( parse_uri( & mut bytes) ) ) ;
566+ self . path = Some ( complete ! ( parse_uri( & mut bytes, config . allow_rfc3986_non_compliant_path ) ) ) ;
543567 if config. allow_multiple_spaces_in_request_line_delimiters {
544568 complete ! ( skip_spaces( & mut bytes) ) ;
545569 }
@@ -952,9 +976,9 @@ fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
952976#[ doc( hidden) ]
953977#[ allow( missing_docs) ]
954978// 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 > {
956980 let start = bytes. pos ( ) ;
957- simd:: match_uri_vectored ( bytes) ;
981+ simd:: match_uri_vectored ( bytes, allow_non_compliant ) ;
958982 let end = bytes. pos ( ) ;
959983
960984 if next ! ( bytes) == b' ' {
@@ -2676,4 +2700,26 @@ mod tests {
26762700 assert_eq ! ( response. headers[ 0 ] . name, "foo" ) ;
26772701 assert_eq ! ( response. headers[ 0 ] . value, & b"bar" [ ..] ) ;
26782702 }
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+ }
26792725}
0 commit comments