@@ -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,49 @@ 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) ) ?;
20142063 let new_scheme_type = SchemeType :: from ( & parser. serialization ) ;
20152064 let old_scheme_type = SchemeType :: from ( self . scheme ( ) ) ;
2016- // Switching from special scheme to non special scheme
2017- // and switching from file to non file is not allowed
2018- if old_scheme_type != new_scheme_type {
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 ( )
2072+ {
20192073 return Err ( ( ) ) ;
20202074 }
20212075
0 commit comments