From 91be07b52446d8e468671d3dbd749b939acac00f Mon Sep 17 00:00:00 2001 From: lenamonj Date: Sun, 9 Aug 2026 09:04:07 -0400 Subject: [PATCH] Fix Windows drive letter normalization in hostless file: URLs parse_path implemented the spec's "url's path is empty" test as segment_start == path_start + 1, which assumes path[0] begins one byte after path_start. A hostless file: URL carries a run of slashes there, because parse_path_start finds "file://" already ending in a slash and returns without adding one, so the drive letter in file:///C|/a was never recognised and the | was never rewritten to :. Derive where path[0] starts instead of assuming it. Removes from url/tests/expected_failures.txt, which the WPT harness now passes. Fixes #889. --- url/src/parser.rs | 13 ++++++++++++- url/tests/expected_failures.txt | 1 - 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/url/src/parser.rs b/url/src/parser.rs index 6ccfa9b46..dbfb92c63 100644 --- a/url/src/parser.rs +++ b/url/src/parser.rs @@ -1323,7 +1323,8 @@ impl Parser<'_> { _ => { // If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then if scheme_type.is_file() - && segment_start == path_start + 1 + && segment_start + == Parser::file_first_segment_start(&self.serialization, path_start) && is_windows_drive_letter(segment_before_slash) { // Replace the second code point in buffer with U+003A (:). @@ -1361,6 +1362,16 @@ impl Parser<'_> { input } + /// The offset at which `path[0]` of a `file:` URL begins. + /// + /// While a hostless `file:` URL is being parsed the serialization carries a + /// run of slashes at `path_start` rather than a single one, so the first + /// segment does not always begin at `path_start + 1`. + fn file_first_segment_start(serialization: &str, path_start: usize) -> usize { + let path = &serialization[path_start..]; + path_start + (path.len() - path.trim_start_matches('/').len()) + } + fn last_slash_can_be_removed(serialization: &str, path_start: usize) -> bool { let url_before_segment = &serialization[..serialization.len() - 1]; if let Some(segment_before_start) = url_before_segment.rfind('/') { diff --git a/url/tests/expected_failures.txt b/url/tests/expected_failures.txt index 314adad59..b5d818ee5 100644 --- a/url/tests/expected_failures.txt +++ b/url/tests/expected_failures.txt @@ -42,7 +42,6 @@ set pathname to set pathname to set pathname to

-