Skip to content

Commit 6637a72

Browse files
authoredMar 11, 2025··
fix: validate path bytes are at least utf8 (#756)
1 parent d0dd91e commit 6637a72

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed
 

‎src/byte_str.rs

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ impl ByteStr {
4545
// Invariant: assumed by the safety requirements of this function.
4646
ByteStr { bytes }
4747
}
48+
49+
pub(crate) fn from_utf8(bytes: Bytes) -> Result<ByteStr, std::str::Utf8Error> {
50+
str::from_utf8(&bytes)?;
51+
// Invariant: just checked is utf8
52+
Ok(ByteStr { bytes })
53+
}
4854
}
4955

5056
impl ops::Deref for ByteStr {

‎src/uri/path.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)
Please sign in to comment.