Skip to content

Commit c97b22f

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

File tree

1 file changed

+72
-5
lines changed

1 file changed

+72
-5
lines changed

src/lib.rs

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,8 +1663,13 @@ impl Url {
16631663
self.set_host_internal(Host::parse_opaque(host_substr)?, None);
16641664
}
16651665
} else if self.has_host() {
1666-
if SchemeType::from(self.scheme()).is_special() {
1666+
let scheme_type = SchemeType::from(self.scheme());
1667+
if scheme_type.is_special() {
16671668
return Err(ParseError::EmptyHost);
1669+
} else {
1670+
if self.serialization.len() == self.path_start as usize {
1671+
self.serialization.push('/');
1672+
}
16681673
}
16691674
debug_assert!(self.byte_at(self.scheme_end) == b':');
16701675
debug_assert!(self.byte_at(self.path_start) == b'/');
@@ -1967,14 +1972,28 @@ impl Url {
19671972
///
19681973
/// # fn run() -> Result<(), ParseError> {
19691974
/// let mut url = Url::parse("https://example.net")?;
1970-
/// let result = url.set_scheme("foo");
1971-
/// assert_eq!(url.as_str(), "foo://example.net/");
1975+
/// let result = url.set_scheme("http");
1976+
/// assert_eq!(url.as_str(), "http://example.net/");
19721977
/// assert!(result.is_ok());
19731978
/// # Ok(())
19741979
/// # }
19751980
/// # run().unwrap();
19761981
/// ```
1982+
/// Change the URL’s scheme from `foo` to `bar`:
19771983
///
1984+
/// ```
1985+
/// use url::Url;
1986+
/// # use url::ParseError;
1987+
///
1988+
/// # fn run() -> Result<(), ParseError> {
1989+
/// let mut url = Url::parse("foo://example.net")?;
1990+
/// let result = url.set_scheme("bar");
1991+
/// assert_eq!(url.as_str(), "bar://example.net");
1992+
/// assert!(result.is_ok());
1993+
/// # Ok(())
1994+
/// # }
1995+
/// # run().unwrap();
1996+
/// ```
19781997
///
19791998
/// Cannot change URL’s scheme from `https` to `foõ`:
19801999
///
@@ -2007,14 +2026,55 @@ impl Url {
20072026
/// # }
20082027
/// # run().unwrap();
20092028
/// ```
2029+
/// Cannot change the URL’s scheme from `foo` to `https`:
2030+
///
2031+
/// ```
2032+
/// use url::Url;
2033+
/// # use url::ParseError;
2034+
///
2035+
/// # fn run() -> Result<(), ParseError> {
2036+
/// let mut url = Url::parse("foo://example.net")?;
2037+
/// let result = url.set_scheme("https");
2038+
/// assert_eq!(url.as_str(), "foo://example.net");
2039+
/// assert!(result.is_err());
2040+
/// # Ok(())
2041+
/// # }
2042+
/// # run().unwrap();
2043+
/// ```
2044+
/// Cannot change the URL’s scheme from `http` to `foo`:
2045+
///
2046+
/// ```
2047+
/// use url::Url;
2048+
/// # use url::ParseError;
2049+
///
2050+
/// # fn run() -> Result<(), ParseError> {
2051+
/// let mut url = Url::parse("http://example.net")?;
2052+
/// let result = url.set_scheme("foo");
2053+
/// assert_eq!(url.as_str(), "http://example.net/");
2054+
/// assert!(result.is_err());
2055+
/// # Ok(())
2056+
/// # }
2057+
/// # run().unwrap();
2058+
/// ```
20102059
pub fn set_scheme(&mut self, scheme: &str) -> Result<(), ()> {
20112060
let mut parser = Parser::for_setter(String::new());
20122061
let remaining = parser.parse_scheme(parser::Input::new(scheme))?;
2013-
if !remaining.is_empty()
2014-
|| (!self.has_host() && SchemeType::from(&parser.serialization).is_special())
2062+
let new_scheme_type = SchemeType::from(&parser.serialization);
2063+
let old_scheme_type = SchemeType::from(self.scheme());
2064+
// If url’s scheme is a special scheme and buffer is not a special scheme, then return.
2065+
if new_scheme_type.is_special() && !old_scheme_type.is_special() ||
2066+
// If url’s scheme is not a special scheme and buffer is a special scheme, then return.
2067+
!new_scheme_type.is_special() && old_scheme_type.is_special() ||
2068+
// If url includes credentials or has a non-null port, and buffer is "file", then return.
2069+
// If url’s scheme is "file" and its host is an empty host or null, then return.
2070+
new_scheme_type.is_file() && self.has_authority()
20152071
{
20162072
return Err(());
20172073
}
2074+
2075+
if !remaining.is_empty() || (!self.has_host() && new_scheme_type.is_special()) {
2076+
return Err(());
2077+
}
20182078
let old_scheme_end = self.scheme_end;
20192079
let new_scheme_end = to_u32(parser.serialization.len()).unwrap();
20202080
let adjust = |index: &mut u32| {
@@ -2036,6 +2096,13 @@ impl Url {
20362096

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

0 commit comments

Comments
 (0)