Skip to content

Commit 0e25146

Browse files
authored
Merge pull request #839 from servo/fix-838
Fix issues with file drives
2 parents 206d378 + 21f32d6 commit 0e25146

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

url/src/parser.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ pub fn default_port(scheme: &str) -> Option<u16> {
178178
}
179179
}
180180

181-
#[derive(Clone)]
181+
#[derive(Clone, Debug)]
182182
pub struct Input<'i> {
183183
chars: str::Chars<'i>,
184184
}
@@ -1173,7 +1173,7 @@ impl<'a> Parser<'a> {
11731173
) -> Input<'i> {
11741174
// Relative path state
11751175
loop {
1176-
let segment_start = self.serialization.len();
1176+
let mut segment_start = self.serialization.len();
11771177
let mut ends_with_slash = false;
11781178
loop {
11791179
let input_before_c = input.clone();
@@ -1202,6 +1202,14 @@ impl<'a> Parser<'a> {
12021202
}
12031203
_ => {
12041204
self.check_url_code_point(c, &input);
1205+
if scheme_type.is_file()
1206+
&& is_normalized_windows_drive_letter(
1207+
&self.serialization[path_start + 1..],
1208+
)
1209+
{
1210+
self.serialization.push('/');
1211+
segment_start += 1;
1212+
}
12051213
if self.context == Context::PathSegmentSetter {
12061214
if scheme_type.is_special() {
12071215
self.serialization
@@ -1249,7 +1257,10 @@ impl<'a> Parser<'a> {
12491257
}
12501258
_ => {
12511259
// If url’s scheme is "file", url’s path is empty, and buffer is a Windows drive letter, then
1252-
if scheme_type.is_file() && is_windows_drive_letter(segment_before_slash) {
1260+
if scheme_type.is_file()
1261+
&& segment_start == path_start + 1
1262+
&& is_windows_drive_letter(segment_before_slash)
1263+
{
12531264
// Replace the second code point in buffer with U+003A (:).
12541265
if let Some(c) = segment_before_slash.chars().next() {
12551266
self.serialization.truncate(segment_start);

url/tests/unit.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,3 +1262,39 @@ fn test_authority() {
12621262
"%C3%A0lex:%C3%[email protected]"
12631263
);
12641264
}
1265+
1266+
#[test]
1267+
/// https://github.com/servo/rust-url/issues/838
1268+
fn test_file_with_drive() {
1269+
let s1 = "fIlE:p:?../";
1270+
let url = url::Url::parse(s1).unwrap();
1271+
assert_eq!(url.to_string(), "file:///p:?../");
1272+
assert_eq!(url.path(), "/p:");
1273+
1274+
let testcases = [
1275+
("a", "file:///p:/a"),
1276+
("", "file:///p:?../"),
1277+
("?x", "file:///p:?x"),
1278+
(".", "file:///p:/"),
1279+
("..", "file:///p:/"),
1280+
("../", "file:///p:/"),
1281+
];
1282+
1283+
for case in &testcases {
1284+
let url2 = url::Url::join(&url, case.0).unwrap();
1285+
assert_eq!(url2.to_string(), case.1);
1286+
}
1287+
}
1288+
1289+
#[test]
1290+
/// Similar to test_file_with_drive, but with a path
1291+
/// that could be confused for a drive.
1292+
fn test_file_with_drive_and_path() {
1293+
let s1 = "fIlE:p:/x|?../";
1294+
let url = url::Url::parse(s1).unwrap();
1295+
assert_eq!(url.to_string(), "file:///p:/x|?../");
1296+
assert_eq!(url.path(), "/p:/x|");
1297+
let s2 = "a";
1298+
let url2 = url::Url::join(&url, s2).unwrap();
1299+
assert_eq!(url2.to_string(), "file:///p:/a");
1300+
}

0 commit comments

Comments
 (0)