@@ -22,6 +22,8 @@ impl PathAndQuery {
22
22
let mut query = NONE ;
23
23
let mut fragment = None ;
24
24
25
+ let mut is_maybe_not_utf8 = false ;
26
+
25
27
// block for iterator borrow
26
28
{
27
29
let mut iter = src. as_ref ( ) . iter ( ) . enumerate ( ) ;
@@ -50,7 +52,12 @@ impl PathAndQuery {
50
52
0x40 ..=0x5F |
51
53
0x61 ..=0x7A |
52
54
0x7C |
53
- 0x7E ..=0xFF => { }
55
+ 0x7E => { }
56
+
57
+ // potentially utf8, might not, should check
58
+ 0x7F ..=0xFF => {
59
+ is_maybe_not_utf8 = true ;
60
+ }
54
61
55
62
// These are code points that are supposed to be
56
63
// percent-encoded in the path but there are clients
@@ -82,7 +89,11 @@ impl PathAndQuery {
82
89
0x21 |
83
90
0x24 ..=0x3B |
84
91
0x3D |
85
- 0x3F ..=0xFF => { }
92
+ 0x3F ..=0x7E => { }
93
+
94
+ 0x7F ..=0xFF => {
95
+ is_maybe_not_utf8 = true ;
96
+ }
86
97
87
98
b'#' => {
88
99
fragment = Some ( i) ;
@@ -99,10 +110,13 @@ impl PathAndQuery {
99
110
src. truncate ( i) ;
100
111
}
101
112
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 } )
106
120
}
107
121
108
122
/// Convert a `PathAndQuery` from a static string.
@@ -566,6 +580,16 @@ mod tests {
566
580
assert_eq ! ( Some ( "pizza=🍕" ) , pq( "/test?pizza=🍕" ) . query( ) ) ;
567
581
}
568
582
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
+
569
593
#[ test]
570
594
fn json_is_fine ( ) {
571
595
assert_eq ! (
0 commit comments