Skip to content

Commit

Permalink
Fix invariants of anarchist URLs + empty fragment
Browse files Browse the repository at this point in the history
  • Loading branch information
qsantos committed Mar 2, 2023
1 parent d74092c commit b0ba159
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 23 deletions.
9 changes: 8 additions & 1 deletion url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,14 @@ impl Url {
assert_eq!(self.host_end, self.scheme_end + 1);
assert_eq!(self.host, HostInternal::None);
assert_eq!(self.port, None);
assert_eq!(self.path_start, self.scheme_end + 1);
if self.path().starts_with("//") {
// special case when first path fragment is empty
assert_eq!(self.byte_at(self.scheme_end + 1), b'/');
assert_eq!(self.byte_at(self.scheme_end + 2), b'.');
assert_eq!(self.path_start, self.scheme_end + 3);
} else {
assert_eq!(self.path_start, self.scheme_end + 1);
}
}
if let Some(start) = self.query_start {
assert!(start >= self.path_start);
Expand Down
25 changes: 12 additions & 13 deletions url/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,19 +467,28 @@ impl<'a> Parser<'a> {
return self.after_double_slash(input, scheme_type, scheme_end);
}
// Anarchist URL (no authority)
let path_start = to_u32(self.serialization.len())?;
let mut path_start = to_u32(self.serialization.len())?;
let username_end = path_start;
let host_start = path_start;
let host_end = path_start;
let host = HostInternal::None;
let port = None;
let remaining = if let Some(input) = input.split_prefix('/') {
let path_start = self.serialization.len();
self.serialization.push('/');
self.parse_path(scheme_type, &mut false, path_start, input)
self.parse_path(scheme_type, &mut false, path_start as usize, input)
} else {
self.parse_cannot_be_a_base_path(input)
};
// This prevents web+demo:/.//not-a-host/ or web+demo:/path/..//not-a-host/,
// when parsed and then serialized, from ending up as web+demo://not-a-host/
// (they end up as web+demo:/.//not-a-host/).
if self.serialization[path_start as usize..].starts_with("//") {
// If url’s host is null, url does not have an opaque path,
// url’s path’s size is greater than 1, and url’s path[0] is the empty string,
// then append U+002F (/) followed by U+002E (.) to output.
self.serialization.insert_str(path_start as usize, "/.");
path_start += 2;
}
self.with_query_and_fragment(
scheme_type,
scheme_end,
Expand Down Expand Up @@ -1281,16 +1290,6 @@ impl<'a> Parser<'a> {
self.serialization.push_str(path.trim_start_matches('/'));
}

// This prevents web+demo:/.//not-a-host/ or web+demo:/path/..//not-a-host/,
// when parsed and then serialized, from ending up as web+demo://not-a-host/
// (they end up as web+demo:/.//not-a-host/).
if !*has_host && self.serialization[path_start..].starts_with("//") {
// If url’s host is null, url does not have an opaque path,
// url’s path’s size is greater than 1, and url’s path[0] is the empty string,
// then append U+002F (/) followed by U+002E (.) to output.
self.serialization.insert_str(path_start, "/.");
}

input
}

Expand Down
9 changes: 8 additions & 1 deletion url/src/slicing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,14 @@ impl Url {
}
}

Position::AfterPort => self.path_start as usize,
Position::AfterPort => {
if let Some(port) = self.port {
debug_assert!(self.byte_at(self.host_end) == b':');
self.host_end as usize + ":".len() + port.to_string().len()
} else {
self.host_end as usize
}
}

Position::BeforePath => self.path_start as usize,

Expand Down
8 changes: 0 additions & 8 deletions url/tests/urltestdata.json
Original file line number Diff line number Diff line change
Expand Up @@ -7487,7 +7487,6 @@
"hash": ""
},
"Serialize /. in path",
"skip next",
{
"input": "non-spec:/.//",
"base": "about:blank",
Expand All @@ -7502,7 +7501,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "non-spec:/..//",
"base": "about:blank",
Expand All @@ -7517,7 +7515,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "non-spec:/a/..//",
"base": "about:blank",
Expand All @@ -7532,7 +7529,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "non-spec:/.//path",
"base": "about:blank",
Expand All @@ -7547,7 +7543,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "non-spec:/..//path",
"base": "about:blank",
Expand All @@ -7562,7 +7557,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "non-spec:/a/..//path",
"base": "about:blank",
Expand Down Expand Up @@ -7637,7 +7631,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "",
"base": "non-spec:/..//p",
Expand All @@ -7652,7 +7645,6 @@
"search": "",
"hash": ""
},
"skip next",
{
"input": "path",
"base": "non-spec:/..//p",
Expand Down

0 comments on commit b0ba159

Please sign in to comment.