Fix Windows drive letter normalization in hostless file: URLs - #1147
Open
lenamonj wants to merge 1 commit into
Open
Fix Windows drive letter normalization in hostless file: URLs#1147lenamonj wants to merge 1 commit into
lenamonj wants to merge 1 commit into
Conversation
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 <file:///w|/m> from url/tests/expected_failures.txt, which the WPT harness now passes. Fixes servo#889.
lenamonj
added a commit
to lenamonj/jeffy-loop
that referenced
this pull request
Aug 9, 2026
servo/rust-url at 00a6ce5, still the tip of upstream main and itself a drive-letter fix merged nine days before the run. Three runs of 30 iterations against a pre-registered budget of five. 20 findings closed, 10 High, none declined; shipped-code change 6 files, +642/-103; all 19 surface-inventory rows swept. The run's own headline is a claim it kept taking back: make_relative was declared class-complete three times and withdrawn three times, twice by the evaluator gate and once by the run's own closing audit, each time because the enumeration behind the claim could not express a shape that still failed. It held at the fourth attempt. The oracle integrity check the target brief specified before iteration 1 is run in the receipt: both vendored WPT corpora byte-identical to pristine upstream by blob hash, wpt.rs unchanged, zero lines added to expected_failures.txt and one removed, the same single #[ignore] before and after. The allowlist moved 67 to 66 in the only direction it can. One finding went upstream as servo/rust-url#1147, which closes their #889, open since 2023. It is the only one of the twenty with evidence outside the loop's own tests, and the receipt says so rather than implying the other nineteen were held back for another reason. ATTEMPTS.md also corrects a stale number of its own: the sqlparse entry said six evaluator rejections where that receipt was corrected to seven.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #889.
Url::parse("file:///C|/hello/world")returnsfile:///C|/hello/world. Per path state the|has to be rewritten: "If url's scheme is 'file', url's path is empty, and buffer is a Windows drive letter, then replace the second code point in buffer with U+003A (:)". The expected output isfile:///C:/hello/world.The repo already records the same defect from the other direction:
<file:///w|/m>sits inurl/tests/expected_failures.txt, and the WPT entry for it expectsfile:///w:/m.Cause
parse_pathimplements the spec's "url's path is empty" test assegment_start == path_start + 1, assumingpath[0]begins one byte afterpath_start. That holds when the serialization carries a single slash there, but afile:URL can end up with a run of them: forfile:///w|/m,parse_path_startfindsfile://already ending in/and returns without adding one, soparse_pathappends its own.Instrumenting the check on
mainshows it directly:The only segment the test accepts is the empty one; the drive letter arrives a slash later and is never rewritten. The spellings that do work today (
file:/C|/a,file://host/C|/a) carry exactly one slash atpath_start, so the test holds there; the failing shapes are the ones that put a run of slashes atpath_start, with the hostlessfile:///form the common case.Fix
Derive where
path[0]actually starts instead of assumingpath_start + 1.Verification
Removing
<file:///w|/m>fromurl/tests/expected_failures.txtis the regression test: the harness grades both directions, so the line fails the suite without the fix and fails it again as an unexpected success if left in place with the fix.On
mainwith only that line removed,cargo test -p url --test url_wptfails:With this change it passes, and the case from #889 returns
file:///C:/hello/world. Also green on x86_64-pc-windows-msvc, rustc 1.90.0:cargo fmt --all --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test,cargo test --features "url/serde,url/expose_internals",cargo test --no-default-features --features=alloc.Behaviour before and after over a grid of 410
file:inputs andjoinpairs: the only differences are drive letters spelled|normalized to:when they form the first path segment. The neighbouring WPT casesfile:///w|mandfile:///w||m, which must keep the|, are unchanged, as arefile:/C|/aandfile://host/C|/a.