Skip to content

Commit a9c7af5

Browse files
committed
Avoid reparse issues with non-special URLs
This is a willfull violation of the URL specification for serialization. It retains spec-compliance for parsing, it aligns with the behavior of Microsoft Edge, and it "fixes" an acknowledged specification bug. See whatwg/url#415 Fixes #397
1 parent 3851a94 commit a9c7af5

File tree

3 files changed

+36
-1
lines changed

3 files changed

+36
-1
lines changed

src/lib.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1035,12 +1035,21 @@ impl Url {
10351035
/// # run().unwrap();
10361036
/// ```
10371037
pub fn path(&self) -> &str {
1038-
match (self.query_start, self.fragment_start) {
1038+
let path = match (self.query_start, self.fragment_start) {
10391039
(None, None) => self.slice(self.path_start..),
10401040
(Some(next_component_start), _) |
10411041
(None, Some(next_component_start)) => {
10421042
self.slice(self.path_start..next_component_start)
10431043
}
1044+
};
1045+
// Disambiguating a path that starts with "//" from a URL with an authority may require
1046+
// the serializer to insert a disambiguating marker to the start of the path.
1047+
// When deserializing, "/./" is supposed to be reduced to "/", so avoid exposing it to
1048+
// the application.
1049+
if path.len() >= 3 && &path[..3] == "/./" {
1050+
&path[2..]
1051+
} else {
1052+
path
10441053
}
10451054
}
10461055

src/parser.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,17 @@ impl<'a> Parser<'a> {
10571057
}
10581058
}
10591059
if ends_with_slash {
1060+
// This is a willfull violation of the URL specification for serialization.
1061+
//
1062+
// It aligns with the behaviour of Microsoft Edge,
1063+
// it does not affect the result of parsing (that's still compliant),
1064+
// and it's necessary to make URL reparsing idempotent.
1065+
//
1066+
// See the specification bug at https://github.com/whatwg/url/issues/415
1067+
if !*has_host && &self.serialization[path_start..] == "/" {
1068+
self.serialization.push('.');
1069+
self.serialization.push('/');
1070+
}
10601071
self.serialization.push('/')
10611072
}
10621073
}

tests/urltestdata.json

+15
Original file line numberDiff line numberDiff line change
@@ -6144,5 +6144,20 @@
61446144
"pathname": "/test",
61456145
"search": "?a",
61466146
"hash": "#bc"
6147+
},
6148+
"Found by fuzzing",
6149+
{
6150+
"input": "a:/a/..//a",
6151+
"base": "about:blank",
6152+
"href": "a:/.//a",
6153+
"protocol": "a:",
6154+
"username": "",
6155+
"password": "",
6156+
"host": "",
6157+
"hostname": "",
6158+
"port": "",
6159+
"pathname": "//a",
6160+
"search": "",
6161+
"hash": ""
61476162
}
61486163
]

0 commit comments

Comments
 (0)