Skip to content

Commit 0790da7

Browse files
committed
Add a shorten_path helper.
1 parent ca879d8 commit 0790da7

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

src/parser.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ impl<'a> Parser<'a> {
638638
(Some(i), _) | (None, Some(i)) => base_url.slice(..i),
639639
};
640640
self.serialization.push_str(before_query);
641-
self.pop_path(SchemeType::File, base_url.path_start as usize);
641+
self.shorten_path(SchemeType::File, base_url.path_start as usize);
642642
let remaining = self.parse_path(
643643
SchemeType::File,
644644
&mut true,
@@ -1157,15 +1157,15 @@ impl<'a> Parser<'a> {
11571157
".." | "%2e%2e" | "%2e%2E" | "%2E%2e" | "%2E%2E" | "%2e." | "%2E." | ".%2e"
11581158
| ".%2E" => {
11591159
debug_assert!(self.serialization.as_bytes()[segment_start - 1] == b'/');
1160-
// We dont want to truncate beyond the path start:
1161-
if segment_start - 1 > path_start {
1162-
self.serialization.truncate(segment_start - 1); // Truncate "/.."
1160+
self.serialization.truncate(segment_start);
1161+
// Do not remove the root slash
1162+
if self.serialization.ends_with("/") && path_start + 1 < segment_start {
1163+
self.serialization.pop();
1164+
self.shorten_path(scheme_type, path_start);
11631165
} else {
1164-
self.serialization.truncate(segment_start); // Truncate ".."
1166+
self.shorten_path(scheme_type, path_start);
11651167
}
11661168

1167-
self.pop_path(scheme_type, path_start);
1168-
11691169
// and then if neither c is U+002F (/), nor url is special and c is U+005C (\), append the empty string to url’s path.
11701170
if ends_with_slash && !self.serialization.ends_with("/") {
11711171
self.serialization.push('/');
@@ -1209,16 +1209,36 @@ impl<'a> Parser<'a> {
12091209
input
12101210
}
12111211

1212+
/// https://url.spec.whatwg.org/#shorten-a-urls-path
1213+
fn shorten_path(&mut self, scheme_type: SchemeType, path_start: usize) {
1214+
// If path is empty, then return.
1215+
if self.serialization.len() <= path_start {
1216+
return;
1217+
}
1218+
// If url’s scheme is "file", path’s size is 1, and path[0] is a normalized Windows drive letter, then return.
1219+
let segments: Vec<&str> = self.serialization[path_start..]
1220+
.split('/')
1221+
.filter(|s| !s.is_empty())
1222+
.collect();
1223+
if scheme_type.is_file()
1224+
&& segments.len() == 1
1225+
&& is_normalized_windows_drive_letter(segments[0])
1226+
{
1227+
return;
1228+
}
1229+
// Remove path’s last item.
1230+
self.pop_path(scheme_type, path_start);
1231+
}
1232+
12121233
/// https://url.spec.whatwg.org/#pop-a-urls-path
12131234
fn pop_path(&mut self, scheme_type: SchemeType, path_start: usize) {
12141235
if self.serialization.len() > path_start {
12151236
let slash_position = self.serialization[path_start..].rfind('/').unwrap();
12161237
// + 1 since rfind returns the position before the slash.
12171238
let segment_start = path_start + slash_position + 1;
12181239
// Don’t pop a Windows drive letter
1219-
// FIXME: *normalized* Windows drive letter
12201240
if !(scheme_type.is_file()
1221-
&& is_windows_drive_letter(&self.serialization[segment_start..]))
1241+
&& is_normalized_windows_drive_letter(&self.serialization[segment_start..]))
12221242
{
12231243
self.serialization.truncate(segment_start);
12241244
}

0 commit comments

Comments
 (0)