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