@@ -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