Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix setting file hosts to None #734

Merged
merged 1 commit into from Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 21 additions & 5 deletions url/src/lib.rs
Expand Up @@ -1813,8 +1813,10 @@ impl Url {
return Err(ParseError::SetHostOnCannotBeABaseUrl);
}

let scheme_type = SchemeType::from(self.scheme());

if let Some(host) = host {
if host.is_empty() && SchemeType::from(self.scheme()).is_special() {
if host.is_empty() && scheme_type.is_special() && !scheme_type.is_file() {
return Err(ParseError::EmptyHost);
}
let mut host_substr = host;
Expand All @@ -1838,15 +1840,20 @@ impl Url {
self.set_host_internal(Host::parse_opaque(host_substr)?, None);
}
} else if self.has_host() {
let scheme_type = SchemeType::from(self.scheme());
if scheme_type.is_special() {
if scheme_type.is_special() && !scheme_type.is_file() {
return Err(ParseError::EmptyHost);
} else if self.serialization.len() == self.path_start as usize {
self.serialization.push('/');
}
debug_assert!(self.byte_at(self.scheme_end) == b':');
debug_assert!(self.byte_at(self.path_start) == b'/');
let new_path_start = self.scheme_end + 1;

let new_path_start = if scheme_type.is_file() {
self.scheme_end + 3
} else {
self.scheme_end + 1
};

self.serialization
.drain(new_path_start as usize..self.path_start as usize);
let offset = self.path_start - new_path_start;
Expand Down Expand Up @@ -2730,6 +2737,7 @@ fn path_to_file_url_segments_windows(
let host_start = serialization.len() + 1;
let host_end;
let host_internal;

match components.next() {
Some(Component::Prefix(ref p)) => match p.kind() {
Prefix::Disk(letter) | Prefix::VerbatimDisk(letter) => {
Expand All @@ -2750,7 +2758,6 @@ fn path_to_file_url_segments_windows(
}
_ => return Err(()),
},

_ => return Err(()),
}

Expand All @@ -2759,19 +2766,23 @@ fn path_to_file_url_segments_windows(
if component == Component::RootDir {
continue;
}

path_only_has_prefix = false;
// FIXME: somehow work with non-unicode?
let component = component.as_os_str().to_str().ok_or(())?;

serialization.push('/');
serialization.extend(percent_encode(component.as_bytes(), PATH_SEGMENT));
}

// A windows drive letter must end with a slash.
if serialization.len() > host_start
&& parser::is_windows_drive_letter(&serialization[host_start..])
&& path_only_has_prefix
{
serialization.push('/');
}

Ok((host_end, host_internal))
}

Expand All @@ -2795,23 +2806,28 @@ fn file_url_segments_to_pathbuf(
} else {
Vec::new()
};

for segment in segments {
bytes.push(b'/');
bytes.extend(percent_decode(segment.as_bytes()));
}

// A windows drive letter must end with a slash.
if bytes.len() > 2
&& matches!(bytes[bytes.len() - 2], b'a'..=b'z' | b'A'..=b'Z')
&& matches!(bytes[bytes.len() - 1], b':' | b'|')
{
bytes.push(b'/');
}

let os_str = OsStr::from_bytes(&bytes);
let path = PathBuf::from(os_str);

debug_assert!(
path.is_absolute(),
"to_file_path() failed to produce an absolute Path"
);

Ok(path)
}

Expand Down
8 changes: 8 additions & 0 deletions url/tests/unit.rs
Expand Up @@ -43,6 +43,14 @@ fn test_set_empty_host() {
assert_eq!(base.as_str(), "moz:/baz");
base.set_host(Some("servo")).unwrap();
assert_eq!(base.as_str(), "moz://servo/baz");

let mut base: Url = "file://server/share/foo/bar".parse().unwrap();
base.set_host(None).unwrap();
assert_eq!(base.as_str(), "file:///share/foo/bar");

let mut base: Url = "file://server/share/foo/bar".parse().unwrap();
base.set_host(Some("foo")).unwrap();
assert_eq!(base.as_str(), "file://foo/share/foo/bar");
}

#[test]
Expand Down