@@ -22,6 +22,8 @@ impl PathAndQuery {
2222 let mut query = NONE ;
2323 let mut fragment = None ;
2424
25+ let mut is_maybe_not_utf8 = false ;
26+
2527 // block for iterator borrow
2628 {
2729 let mut iter = src. as_ref ( ) . iter ( ) . enumerate ( ) ;
@@ -50,7 +52,12 @@ impl PathAndQuery {
5052 0x40 ..=0x5F |
5153 0x61 ..=0x7A |
5254 0x7C |
53- 0x7E ..=0xFF => { }
55+ 0x7E => { }
56+
57+ // potentially utf8, might not, should check
58+ 0x7F ..=0xFF => {
59+ is_maybe_not_utf8 = true ;
60+ }
5461
5562 // These are code points that are supposed to be
5663 // percent-encoded in the path but there are clients
@@ -82,7 +89,11 @@ impl PathAndQuery {
8289 0x21 |
8390 0x24 ..=0x3B |
8491 0x3D |
85- 0x3F ..=0xFF => { }
92+ 0x3F ..=0x7E => { }
93+
94+ 0x7F ..=0xFF => {
95+ is_maybe_not_utf8 = true ;
96+ }
8697
8798 b'#' => {
8899 fragment = Some ( i) ;
@@ -99,10 +110,13 @@ impl PathAndQuery {
99110 src. truncate ( i) ;
100111 }
101112
102- Ok ( PathAndQuery {
103- data : unsafe { ByteStr :: from_utf8_unchecked ( src) } ,
104- query,
105- } )
113+ let data = if is_maybe_not_utf8 {
114+ ByteStr :: from_utf8 ( src) . map_err ( |_| ErrorKind :: InvalidUriChar ) ?
115+ } else {
116+ unsafe { ByteStr :: from_utf8_unchecked ( src) }
117+ } ;
118+
119+ Ok ( PathAndQuery { data, query } )
106120 }
107121
108122 /// Convert a `PathAndQuery` from a static string.
@@ -566,6 +580,16 @@ mod tests {
566580 assert_eq ! ( Some ( "pizza=🍕" ) , pq( "/test?pizza=🍕" ) . query( ) ) ;
567581 }
568582
583+ #[ test]
584+ fn rejects_invalid_utf8_in_path ( ) {
585+ PathAndQuery :: try_from ( & [ b'/' , 0xFF ] [ ..] ) . expect_err ( "reject invalid utf8" ) ;
586+ }
587+
588+ #[ test]
589+ fn rejects_invalid_utf8_in_query ( ) {
590+ PathAndQuery :: try_from ( & [ b'/' , b'a' , b'?' , 0xFF ] [ ..] ) . expect_err ( "reject invalid utf8" ) ;
591+ }
592+
569593 #[ test]
570594 fn json_is_fine ( ) {
571595 assert_eq ! (
0 commit comments