Skip to content

Commit

Permalink
Normalize URL paths: convert /.//p, /..//p, and //p to p
Browse files Browse the repository at this point in the history
  • Loading branch information
theskim committed Oct 8, 2024
1 parent a6e704f commit fc16d17
Showing 1 changed file with 21 additions and 24 deletions.
45 changes: 21 additions & 24 deletions url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,16 @@ impl Url {
let old_after_path_pos = to_u32(self.serialization.len()).unwrap();
let cannot_be_a_base = self.cannot_be_a_base();
let scheme_type = SchemeType::from(self.scheme());
let mut path_empty = false;
let mut has_host = if let Some(index) = self.serialization.find(":/") {
let rest = &self.serialization[(index + ":/".len())..];
let host_part = rest.split('/').next().unwrap_or("");
path_empty = rest.is_empty();
!host_part.is_empty() && !host_part.contains('@')
} else {
false
};

self.serialization.truncate(self.path_start as usize);
self.mutate(|parser| {
if cannot_be_a_base {
Expand All @@ -1718,7 +1728,6 @@ impl Url {
}
parser.parse_cannot_be_a_base_path(parser::Input::new_no_trim(path));
} else {
let mut has_host = true; // FIXME
parser.parse_path_start(
scheme_type,
&mut has_host,
Expand All @@ -1727,29 +1736,17 @@ impl Url {
}
});

// To handle cases like <non-spec:/> set pathname to </..//p>
// For instance, //p should be converted to /..//p here
// At this point, we would get "non-spec://p" for serialization
// and "/..//p" for path
if let Some(path_pos) = path.rfind("//") {
if let Some(serialization_pos) = self.serialization.rfind("//") {
const PATH_INCREMENT: usize = 2; // length of "/."

if path_pos + PATH_INCREMENT <= path.len()
&& serialization_pos + PATH_INCREMENT <= self.serialization.len()
{
let rest_path = &path[(path_pos + PATH_INCREMENT)..];
let rest_serialization =
&self.serialization[(serialization_pos + PATH_INCREMENT)..];

// rest should be the same
if rest_path == rest_serialization {
self.serialization
.replace_range(serialization_pos.., &format!("/.//{}", rest_path));
self.path_start += PATH_INCREMENT as u32;
}
}
}
// Append "/." immediately after the scheme (up to ":")
// This is done if three conditions are met.
// https://url.spec.whatwg.org/#url-serializing
// 1. The host is null
// 2. The url's path length is greater than 1
// 3. the first segment of the URL's path is an empty string
if !has_host && path.len() > 1 && path_empty {
if let Some(index) = self.serialization.find("://") {
self.serialization.insert_str(index + ":".len(), "/.");
self.path_start += "/.".len() as u32;
}
}

self.restore_after_path(old_after_path_pos, &after_path);
Expand Down

0 comments on commit fc16d17

Please sign in to comment.