@@ -1659,8 +1659,13 @@ impl Url {
16591659 self . set_host_internal ( Host :: parse_opaque ( host_substr) ?, None ) ;
16601660 }
16611661 } else if self . has_host ( ) {
1662- if SchemeType :: from ( self . scheme ( ) ) . is_special ( ) {
1662+ let scheme_type = SchemeType :: from ( self . scheme ( ) ) ;
1663+ if scheme_type. is_special ( ) {
16631664 return Err ( ParseError :: EmptyHost ) ;
1665+ } else {
1666+ if self . serialization . len ( ) == self . path_start as usize {
1667+ self . serialization . push ( '/' ) ;
1668+ }
16641669 }
16651670 debug_assert ! ( self . byte_at( self . scheme_end) == b':' ) ;
16661671 debug_assert ! ( self . byte_at( self . path_start) == b'/' ) ;
@@ -1963,14 +1968,28 @@ impl Url {
19631968 ///
19641969 /// # fn run() -> Result<(), ParseError> {
19651970 /// let mut url = Url::parse("https://example.net")?;
1966- /// let result = url.set_scheme("foo ");
1967- /// assert_eq!(url.as_str(), "foo ://example.net/");
1971+ /// let result = url.set_scheme("http ");
1972+ /// assert_eq!(url.as_str(), "http ://example.net/");
19681973 /// assert!(result.is_ok());
19691974 /// # Ok(())
19701975 /// # }
19711976 /// # run().unwrap();
19721977 /// ```
1978+ /// Change the URL’s scheme from `foo` to `bar`:
19731979 ///
1980+ /// ```
1981+ /// use url::Url;
1982+ /// # use url::ParseError;
1983+ ///
1984+ /// # fn run() -> Result<(), ParseError> {
1985+ /// let mut url = Url::parse("foo://example.net")?;
1986+ /// let result = url.set_scheme("bar");
1987+ /// assert_eq!(url.as_str(), "bar://example.net");
1988+ /// assert!(result.is_ok());
1989+ /// # Ok(())
1990+ /// # }
1991+ /// # run().unwrap();
1992+ /// ```
19741993 ///
19751994 /// Cannot change URL’s scheme from `https` to `foõ`:
19761995 ///
@@ -2003,14 +2022,49 @@ impl Url {
20032022 /// # }
20042023 /// # run().unwrap();
20052024 /// ```
2025+ /// Cannot change the URL’s scheme from `foo` to `https`:
2026+ ///
2027+ /// ```
2028+ /// use url::Url;
2029+ /// # use url::ParseError;
2030+ ///
2031+ /// # fn run() -> Result<(), ParseError> {
2032+ /// let mut url = Url::parse("foo://example.net")?;
2033+ /// let result = url.set_scheme("https");
2034+ /// assert_eq!(url.as_str(), "foo://example.net");
2035+ /// assert!(result.is_err());
2036+ /// # Ok(())
2037+ /// # }
2038+ /// # run().unwrap();
2039+ /// ```
2040+ /// Cannot change the URL’s scheme from `http` to `foo`:
2041+ ///
2042+ /// ```
2043+ /// use url::Url;
2044+ /// # use url::ParseError;
2045+ ///
2046+ /// # fn run() -> Result<(), ParseError> {
2047+ /// let mut url = Url::parse("http://example.net")?;
2048+ /// let result = url.set_scheme("foo");
2049+ /// assert_eq!(url.as_str(), "http://example.net/");
2050+ /// assert!(result.is_err());
2051+ /// # Ok(())
2052+ /// # }
2053+ /// # run().unwrap();
2054+ /// ```
20062055 pub fn set_scheme ( & mut self , scheme : & str ) -> Result < ( ) , ( ) > {
20072056 let mut parser = Parser :: for_setter ( String :: new ( ) ) ;
20082057 let remaining = parser. parse_scheme ( parser:: Input :: new ( scheme) ) ?;
20092058 let new_scheme_type = SchemeType :: from ( & parser. serialization ) ;
20102059 let old_scheme_type = SchemeType :: from ( self . scheme ( ) ) ;
2011- // Switching from special scheme to non special scheme
2012- // and switching from file to non file is not allowed
2013- if old_scheme_type != new_scheme_type {
2060+ // If url’s scheme is a special scheme and buffer is not a special scheme, then return.
2061+ if new_scheme_type. is_special ( ) && !old_scheme_type. is_special ( ) ||
2062+ // If url’s scheme is not a special scheme and buffer is a special scheme, then return.
2063+ !new_scheme_type. is_special ( ) && old_scheme_type. is_special ( ) ||
2064+ // If url includes credentials or has a non-null port, and buffer is "file", then return.
2065+ // If url’s scheme is "file" and its host is an empty host or null, then return.
2066+ new_scheme_type. is_file ( ) && self . has_authority ( )
2067+ {
20142068 return Err ( ( ) ) ;
20152069 }
20162070
0 commit comments