From eb3f20d7e4da46344b9bb8e1c54d2f64034b1f59 Mon Sep 17 00:00:00 2001 From: Andrew Banchich Date: Tue, 6 Sep 2022 18:18:28 -0400 Subject: [PATCH] Fix setting file hosts to None --- url/src/lib.rs | 26 +++++++++++++++++++++----- url/tests/unit.rs | 8 ++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/url/src/lib.rs b/url/src/lib.rs index 967282e56..e359e74ae 100644 --- a/url/src/lib.rs +++ b/url/src/lib.rs @@ -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; @@ -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; @@ -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) => { @@ -2750,7 +2758,6 @@ fn path_to_file_url_segments_windows( } _ => return Err(()), }, - _ => return Err(()), } @@ -2759,12 +2766,15 @@ 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..]) @@ -2772,6 +2782,7 @@ fn path_to_file_url_segments_windows( { serialization.push('/'); } + Ok((host_end, host_internal)) } @@ -2795,10 +2806,12 @@ 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') @@ -2806,12 +2819,15 @@ fn file_url_segments_to_pathbuf( { 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) } diff --git a/url/tests/unit.rs b/url/tests/unit.rs index 401eaf983..b0dbd57f9 100644 --- a/url/tests/unit.rs +++ b/url/tests/unit.rs @@ -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]