Skip to content

Commit

Permalink
Merge pull request #839 from servo/fix-838
Browse files Browse the repository at this point in the history
Fix issues with file drives
  • Loading branch information
valenting committed Jun 1, 2023
2 parents 206d378 + 21f32d6 commit 0e25146
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 3 deletions.
17 changes: 14 additions & 3 deletions url/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ pub fn default_port(scheme: &str) -> Option<u16> {
}
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Input<'i> {
chars: str::Chars<'i>,
}
Expand Down Expand Up @@ -1173,7 +1173,7 @@ impl<'a> Parser<'a> {
) -> Input<'i> {
// Relative path state
loop {
let segment_start = self.serialization.len();
let mut segment_start = self.serialization.len();
let mut ends_with_slash = false;
loop {
let input_before_c = input.clone();
Expand Down Expand Up @@ -1202,6 +1202,14 @@ impl<'a> Parser<'a> {
}
_ => {
self.check_url_code_point(c, &input);
if scheme_type.is_file()
&& is_normalized_windows_drive_letter(
&self.serialization[path_start + 1..],
)
{
self.serialization.push('/');
segment_start += 1;
}
if self.context == Context::PathSegmentSetter {
if scheme_type.is_special() {
self.serialization
Expand Down Expand Up @@ -1249,7 +1257,10 @@ impl<'a> Parser<'a> {
}
_ => {
// If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then
if scheme_type.is_file() && is_windows_drive_letter(segment_before_slash) {
if scheme_type.is_file()
&& segment_start == path_start + 1
&& is_windows_drive_letter(segment_before_slash)
{
// Replace the second code point in buffer with U+003A (:).
if let Some(c) = segment_before_slash.chars().next() {
self.serialization.truncate(segment_start);
Expand Down
36 changes: 36 additions & 0 deletions url/tests/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1262,3 +1262,39 @@ fn test_authority() {
"%C3%A0lex:%C3%A0lex@xn--lex-8ka.xn--p1ai.example.com"
);
}

#[test]
/// https://github.com/servo/rust-url/issues/838
fn test_file_with_drive() {
let s1 = "fIlE:p:?../";
let url = url::Url::parse(s1).unwrap();
assert_eq!(url.to_string(), "file:///p:?../");
assert_eq!(url.path(), "/p:");

let testcases = [
("a", "file:///p:/a"),
("", "file:///p:?../"),
("?x", "file:///p:?x"),
(".", "file:///p:/"),
("..", "file:///p:/"),
("../", "file:///p:/"),
];

for case in &testcases {
let url2 = url::Url::join(&url, case.0).unwrap();
assert_eq!(url2.to_string(), case.1);
}
}

#[test]
/// Similar to test_file_with_drive, but with a path
/// that could be confused for a drive.
fn test_file_with_drive_and_path() {
let s1 = "fIlE:p:/x|?../";
let url = url::Url::parse(s1).unwrap();
assert_eq!(url.to_string(), "file:///p:/x|?../");
assert_eq!(url.path(), "/p:/x|");
let s2 = "a";
let url2 = url::Url::join(&url, s2).unwrap();
assert_eq!(url2.to_string(), "file:///p:/a");
}

0 comments on commit 0e25146

Please sign in to comment.