Skip to content

Commit dfeb5a5

Browse files
committed
Fix scheme setter
> test result: FAILED. 650 passed; 63 failed; 0 ignored; 0 measured
1 parent 59b6962 commit dfeb5a5

File tree

1 file changed

+72
-5
lines changed

1 file changed

+72
-5
lines changed

src/lib.rs

+72-5
Original file line numberDiff line numberDiff line change
@@ -1664,8 +1664,13 @@ impl Url {
16641664
self.set_host_internal(Host::parse_opaque(host_substr)?, None);
16651665
}
16661666
} else if self.has_host() {
1667-
if SchemeType::from(self.scheme()).is_special() {
1667+
let scheme_type = SchemeType::from(self.scheme());
1668+
if scheme_type.is_special() {
16681669
return Err(ParseError::EmptyHost);
1670+
} else {
1671+
if self.serialization.len() == self.path_start as usize {
1672+
self.serialization.push('/');
1673+
}
16691674
}
16701675
debug_assert!(self.byte_at(self.scheme_end) == b':');
16711676
debug_assert!(self.byte_at(self.path_start) == b'/');
@@ -1968,14 +1973,28 @@ impl Url {
19681973
///
19691974
/// # fn run() -> Result<(), ParseError> {
19701975
/// let mut url = Url::parse("https://example.net")?;
1971-
/// let result = url.set_scheme("foo");
1972-
/// assert_eq!(url.as_str(), "foo://example.net/");
1976+
/// let result = url.set_scheme("http");
1977+
/// assert_eq!(url.as_str(), "http://example.net/");
19731978
/// assert!(result.is_ok());
19741979
/// # Ok(())
19751980
/// # }
19761981
/// # run().unwrap();
19771982
/// ```
1983+
/// Change the URL’s scheme from `foo` to `bar`:
19781984
///
1985+
/// ```
1986+
/// use url::Url;
1987+
/// # use url::ParseError;
1988+
///
1989+
/// # fn run() -> Result<(), ParseError> {
1990+
/// let mut url = Url::parse("foo://example.net")?;
1991+
/// let result = url.set_scheme("bar");
1992+
/// assert_eq!(url.as_str(), "bar://example.net");
1993+
/// assert!(result.is_ok());
1994+
/// # Ok(())
1995+
/// # }
1996+
/// # run().unwrap();
1997+
/// ```
19791998
///
19801999
/// Cannot change URL’s scheme from `https` to `foõ`:
19812000
///
@@ -2008,14 +2027,55 @@ impl Url {
20082027
/// # }
20092028
/// # run().unwrap();
20102029
/// ```
2030+
/// Cannot change the URL’s scheme from `foo` to `https`:
2031+
///
2032+
/// ```
2033+
/// use url::Url;
2034+
/// # use url::ParseError;
2035+
///
2036+
/// # fn run() -> Result<(), ParseError> {
2037+
/// let mut url = Url::parse("foo://example.net")?;
2038+
/// let result = url.set_scheme("https");
2039+
/// assert_eq!(url.as_str(), "foo://example.net");
2040+
/// assert!(result.is_err());
2041+
/// # Ok(())
2042+
/// # }
2043+
/// # run().unwrap();
2044+
/// ```
2045+
/// Cannot change the URL’s scheme from `http` to `foo`:
2046+
///
2047+
/// ```
2048+
/// use url::Url;
2049+
/// # use url::ParseError;
2050+
///
2051+
/// # fn run() -> Result<(), ParseError> {
2052+
/// let mut url = Url::parse("http://example.net")?;
2053+
/// let result = url.set_scheme("foo");
2054+
/// assert_eq!(url.as_str(), "http://example.net/");
2055+
/// assert!(result.is_err());
2056+
/// # Ok(())
2057+
/// # }
2058+
/// # run().unwrap();
2059+
/// ```
20112060
pub fn set_scheme(&mut self, scheme: &str) -> Result<(), ()> {
20122061
let mut parser = Parser::for_setter(String::new());
20132062
let remaining = parser.parse_scheme(parser::Input::new(scheme))?;
2014-
if !remaining.is_empty()
2015-
|| (!self.has_host() && SchemeType::from(&parser.serialization).is_special())
2063+
let new_scheme_type = SchemeType::from(&parser.serialization);
2064+
let old_scheme_type = SchemeType::from(self.scheme());
2065+
// If url’s scheme is a special scheme and buffer is not a special scheme, then return.
2066+
if new_scheme_type.is_special() && !old_scheme_type.is_special() ||
2067+
// If url’s scheme is not a special scheme and buffer is a special scheme, then return.
2068+
!new_scheme_type.is_special() && old_scheme_type.is_special() ||
2069+
// If url includes credentials or has a non-null port, and buffer is "file", then return.
2070+
// If url’s scheme is "file" and its host is an empty host or null, then return.
2071+
new_scheme_type.is_file() && self.has_authority()
20162072
{
20172073
return Err(());
20182074
}
2075+
2076+
if !remaining.is_empty() || (!self.has_host() && new_scheme_type.is_special()) {
2077+
return Err(());
2078+
}
20192079
let old_scheme_end = self.scheme_end;
20202080
let new_scheme_end = to_u32(parser.serialization.len()).unwrap();
20212081
let adjust = |index: &mut u32| {
@@ -2037,6 +2097,13 @@ impl Url {
20372097

20382098
parser.serialization.push_str(self.slice(old_scheme_end..));
20392099
self.serialization = parser.serialization;
2100+
2101+
// Update the port so it can be removed
2102+
// If it is the scheme's default
2103+
// We don't mind it silently failing
2104+
// If there was no port in the first place
2105+
let _ = self.set_port(self.port());
2106+
20402107
Ok(())
20412108
}
20422109

0 commit comments

Comments
 (0)