Bug 1324193 - Bump rust-url to 1.2.4; r?valentin draft
authorManish Goregaokar <manishearth@gmail.com>
Sat, 17 Dec 2016 03:03:35 -0800
changeset 450614 e6930cdb718d947b915227f213b77e3c845fc328
parent 450591 34a1ab064cb5b868fa75cb74d052e978eb34d6c1
child 539809 d8efad2e7eec9521b93f66f2d2136989283f40c5
push id38923
push userbmo:manishearth@gmail.com
push dateSat, 17 Dec 2016 11:04:10 +0000
reviewersvalentin
bugs1324193
milestone53.0a1
Bug 1324193 - Bump rust-url to 1.2.4; r?valentin MozReview-Commit-ID: 2EBQs6hIpku
third_party/rust/url/.cargo-checksum.json
third_party/rust/url/Cargo.toml
third_party/rust/url/rust-url-todo
third_party/rust/url/src/host.rs
third_party/rust/url/src/lib.rs
third_party/rust/url/src/parser.rs
third_party/rust/url/tests/setters_tests.json
third_party/rust/url/tests/unit.rs
third_party/rust/url/tests/urltestdata.json
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/third_party/rust/url/.cargo-checksum.json
+++ b/third_party/rust/url/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"e20a03cb660e0039506f8828204fd93815ebfe051ef62194f8dcf3fc8b7d0e5a",".travis.yml":"2a3033f9edf86bc829de486fc1e74fe0bbe3166ed99b0139754ea29772c19b06","Cargo.toml":"30055a6d4ff3d1bf29a9fa99401e4ffffeecc4b5bade830843a9a5f1634fefd1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e","Makefile":"92b64915724e3b5fec95ec96c5af738bd219b80709e18bf8639d784bc3d9a600","README.md":"eb3f4694003f408cbe3c7f3e9fbbc71241defb940cc55a816981f0f0f144c8eb","UPGRADING.md":"fbcc2d39bdf17db0745793db6626fcd5c909dddd4ce13b27566cfabece22c368","appveyor.yml":"c78486dbfbe6ebbf3d808afb9a19f7ec18c4704ce451c6305f0716999b70a1a6","docs/.nojekyll":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","docs/404.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","docs/index.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","github.png":"b432fd855efe7c430fe6a57ccf83935c1996f03a7cdc8d6e1b34154b8c43f6ec","rust-url-todo":"1192cee7b6cedf2133d97dc6074b593a1d19b0ee13fff6f28d6329855044e575","src/encoding.rs":"7fb43e1c109bf9f2a80a05525082f90e79dba8e8056547571c49fba074406d39","src/form_urlencoded.rs":"172922f2c51eb8dae0182d70e5e0c2969f1b5b7aac026720ced9f84059465999","src/host.rs":"a654dc3c9ce9024b98698e000bc97abaac7f10c49b1635be8125cf72376fd5d1","src/lib.rs":"c3542aabc733f76a3b9c7d24b5c41e60e9eb84d2712660611300d1de0e7c2072","src/origin.rs":"d52010a280d363aed6832f7de5e52c1a62815302e59dcbc9cdc2574e2ac884b9","src/parser.rs":"8ca331ada66f309e91fcc375d8467c929b453979fe0ac5abe190eb8a32074db8","src/path_segments.rs":"0414985c441d0c0292ccc6f56a144b84728ae03382476e6cae1a766f8c333ef8","src/percent_encoding.rs":"44d3321eaa1c77715e9ea1421519289ca73612a31c3d6fce04ff489dfa7db3c5","src/quirks.rs":"3249d1a1f73dd29ec06d626ea2ea4d61e7b2a782543742a5bee422b2f3864b19","src/slicing.rs":"4e539886b23945a92094625f3e531a4bff40daa44240b5d19ee8577478c4f7fe","tests/data.rs":"d36f0ee509fb00524635a7968e336bb89674a82a4fcb06be189155e4b9d43db5","tests/setters_tests.json":"ebb439306ea748be6d0f93132cb59220c5805afd56357d6017f1eb1e4f0f80b3","tests/unit.rs":"9a05f55c7b381b58ee67ef8ef145220e5df88a403225a1a324a36afc9bb6a7d7","tests/urltestdata.json":"11abe4a459566c3929e3326828f8576cb59ec8fab1d191714c34eac28d5f15f9"},"package":"8527c62d9869a08325c38272b3f85668df22a65890c61a639d233dc0ed0b23a2"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"e20a03cb660e0039506f8828204fd93815ebfe051ef62194f8dcf3fc8b7d0e5a",".travis.yml":"2a3033f9edf86bc829de486fc1e74fe0bbe3166ed99b0139754ea29772c19b06","Cargo.toml":"c852af4c69ac79e8c960174967ab94c43f85bcf4bd6c373e402983fb5c121249","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e","Makefile":"92b64915724e3b5fec95ec96c5af738bd219b80709e18bf8639d784bc3d9a600","README.md":"eb3f4694003f408cbe3c7f3e9fbbc71241defb940cc55a816981f0f0f144c8eb","UPGRADING.md":"fbcc2d39bdf17db0745793db6626fcd5c909dddd4ce13b27566cfabece22c368","appveyor.yml":"c78486dbfbe6ebbf3d808afb9a19f7ec18c4704ce451c6305f0716999b70a1a6","docs/.nojekyll":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","docs/404.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","docs/index.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","github.png":"b432fd855efe7c430fe6a57ccf83935c1996f03a7cdc8d6e1b34154b8c43f6ec","src/encoding.rs":"7fb43e1c109bf9f2a80a05525082f90e79dba8e8056547571c49fba074406d39","src/form_urlencoded.rs":"172922f2c51eb8dae0182d70e5e0c2969f1b5b7aac026720ced9f84059465999","src/host.rs":"2225e135e86aa3d1c2d8aedb106cc10700958c94f721072ff62162dc7010b541","src/lib.rs":"83d02c956615925c8f96a904130af4f84bb9997fbdf8e5272723b609039a559a","src/origin.rs":"d52010a280d363aed6832f7de5e52c1a62815302e59dcbc9cdc2574e2ac884b9","src/parser.rs":"4ab643e63e6457bf2f108be8af1d0eed79ade3e0f66fb842d024d8345a9165d7","src/path_segments.rs":"0414985c441d0c0292ccc6f56a144b84728ae03382476e6cae1a766f8c333ef8","src/percent_encoding.rs":"44d3321eaa1c77715e9ea1421519289ca73612a31c3d6fce04ff489dfa7db3c5","src/quirks.rs":"3249d1a1f73dd29ec06d626ea2ea4d61e7b2a782543742a5bee422b2f3864b19","src/slicing.rs":"4e539886b23945a92094625f3e531a4bff40daa44240b5d19ee8577478c4f7fe","tests/data.rs":"d36f0ee509fb00524635a7968e336bb89674a82a4fcb06be189155e4b9d43db5","tests/setters_tests.json":"ebcbdb52e9a4b5a565f8806d52ebc610d46a34df883e10b0be080d026468ff73","tests/unit.rs":"eb320610de77c08d73909cf15ef53e0e032ca03a6b0851dec3f7cbc62b5ec572","tests/urltestdata.json":"a6926f9a39daecde55046fde050ae81a6783ba0a743a106413042bee93d3c106"},"package":"f024e241a55f5c88401595adc1d4af0c9649e91da82d0e190fe55950231ae575"}
\ No newline at end of file
--- a/third_party/rust/url/Cargo.toml
+++ b/third_party/rust/url/Cargo.toml
@@ -1,12 +1,12 @@
 [package]
 
 name = "url"
-version = "1.2.1"
+version = "1.2.4"
 authors = ["The rust-url developers"]
 
 description = "URL library for Rust, based on the WHATWG URL Standard"
 documentation = "http://servo.github.io/rust-url/url/index.html"
 repository = "https://github.com/servo/rust-url"
 readme = "README.md"
 keywords = ["url", "parser"]
 license = "MIT/Apache-2.0"
deleted file mode 100644
--- a/third_party/rust/url/rust-url-todo
+++ /dev/null
@@ -1,14 +0,0 @@
-* standalone path parsing?
-* Test setters
-  * Test trim C0/space
-  * Test remove tab & newline
-
-
-
-#[test]
-fn test_path_segments() {
-    let mut url = Url::parse("http://example.net").unwrap();
-    url.push_path_segment("foo").unwrap();
-    url.extend_path_segments(&["bar", "b/az"]).unwrap();
-    assert_eq!(url.as_str(), "http://example.net/foo");
-}
--- a/third_party/rust/url/src/host.rs
+++ b/third_party/rust/url/src/host.rs
@@ -115,16 +115,17 @@ impl<S: AsRef<str>> fmt::Display for Hos
                 f.write_str("]")
             }
         }
     }
 }
 
 /// This mostly exists because coherence rules don’t allow us to implement
 /// `ToSocketAddrs for (Host<S>, u16)`.
+#[derive(Clone)]
 pub struct HostAndPort<S=String> {
     pub host: Host<S>,
     pub port: u16,
 }
 
 impl<'a> HostAndPort<&'a str> {
     /// Return a copy of `self` that owns an allocated `String` but does not borrow an `&Url`.
     pub fn to_owned(&self) -> HostAndPort<String> {
@@ -366,33 +367,43 @@ fn parse_ipv6addr(input: &str) -> ParseR
     }
 
     if is_ip_v4 {
         if piece_pointer > 6 {
             return Err(ParseError::InvalidIpv6Address)
         }
         let mut dots_seen = 0;
         while i < len {
-            // FIXME: https://github.com/whatwg/url/commit/1c22aa119c354e0020117e02571cec53f7c01064
-            let mut value = 0u16;
+            let mut value = None;
             while i < len {
                 let digit = match input[i] {
                     c @ b'0' ... b'9' => c - b'0',
                     _ => break
                 };
-                value = value * 10 + digit as u16;
-                if value == 0 || value > 255 {
-                    return Err(ParseError::InvalidIpv6Address)
+                match value {
+                    None => value = Some(digit as u16),
+                    Some(0) => return Err(ParseError::InvalidIpv6Address),  // No leading zero
+                    Some(ref mut v) => {
+                        *v = *v * 10 + digit as u16;
+                        if *v > 255 {
+                            return Err(ParseError::InvalidIpv6Address)
+                        }
+                    }
                 }
+                i += 1;
             }
             if dots_seen < 3 && !(i < len && input[i] == b'.') {
                 return Err(ParseError::InvalidIpv6Address)
             }
-            pieces[piece_pointer] = pieces[piece_pointer] * 0x100 + value;
-            if dots_seen == 0 || dots_seen == 2 {
+            pieces[piece_pointer] = if let Some(v) = value {
+                pieces[piece_pointer] * 0x100 + v
+            } else {
+                return Err(ParseError::InvalidIpv6Address)
+            };
+            if dots_seen == 1 || dots_seen == 3 {
                 piece_pointer += 1;
             }
             i += 1;
             if dots_seen == 3 && i < len {
                 return Err(ParseError::InvalidIpv6Address)
             }
             dots_seen += 1;
         }
--- a/third_party/rust/url/src/lib.rs
+++ b/third_party/rust/url/src/lib.rs
@@ -223,22 +223,50 @@ impl<'a> ParseOptions<'a> {
             log_syntax_violation: self.log_syntax_violation,
             context: Context::UrlParser,
         }.parse_url(input)
     }
 }
 
 impl Url {
     /// Parse an absolute URL from a string.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://example.net").unwrap();
+    /// ```
     #[inline]
     pub fn parse(input: &str) -> Result<Url, ::ParseError> {
         Url::options().parse(input)
     }
 
     /// Parse a string as an URL, with this URL as the base URL.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://example.net").unwrap();
+    /// let url = url.join("foo").unwrap();
+    /// assert_eq!(url.as_str(), "https://example.net/foo");
+    /// ```
+    ///
+    /// Trailing slashes are not preserved:
+    ///
+    /// ```rust
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://example.net/foo/").unwrap();
+    /// let url = url.join("bar").unwrap();
+    /// assert_eq!(url.as_str(), "https://example.net/foo/bar");
+    /// ```
     #[inline]
     pub fn join(&self, input: &str) -> Result<Url, ::ParseError> {
         Url::options().base_url(Some(self)).parse(input)
     }
 
     /// Return a default `ParseOptions` that can fully configure the URL parser.
     pub fn options<'a>() -> ParseOptions<'a> {
         ParseOptions {
@@ -246,24 +274,44 @@ impl Url {
             encoding_override: EncodingOverride::utf8(),
             log_syntax_violation: None,
         }
     }
 
     /// Return the serialization of this URL.
     ///
     /// This is fast since that serialization is already stored in the `Url` struct.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use url::Url;
+    ///
+    /// let url_str = "https://example.net/";
+    /// let url = Url::parse(url_str).unwrap();
+    /// assert_eq!(url.as_str(), url_str);
+    /// ```
     #[inline]
     pub fn as_str(&self) -> &str {
         &self.serialization
     }
 
     /// Return the serialization of this URL.
     ///
     /// This consumes the `Url` and takes ownership of the `String` stored in it.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use url::Url;
+    ///
+    /// let url_str = "https://example.net/";
+    /// let url = Url::parse(url_str).unwrap();
+    /// assert_eq!(url.into_string(), url_str);
+    /// ```
     #[inline]
     pub fn into_string(self) -> String {
         self.serialization
     }
 
     /// For internal testing, not part of the public API.
     ///
     /// Methods of the `Url` struct assume a number of invariants.
@@ -309,17 +357,20 @@ impl Url {
                 _ => assert_eq!(self.username_end, self.scheme_end + 3),
             }
             assert!(self.host_start >= self.username_end);
             assert!(self.host_end >= self.host_start);
             let host_str = self.slice(self.host_start..self.host_end);
             match self.host {
                 HostInternal::None => assert_eq!(host_str, ""),
                 HostInternal::Ipv4(address) => assert_eq!(host_str, address.to_string()),
-                HostInternal::Ipv6(address) => assert_eq!(host_str, format!("[{}]", address)),
+                HostInternal::Ipv6(address) => {
+                    let h: Host<String> = Host::Ipv6(address);
+                    assert_eq!(host_str, h.to_string())
+                }
                 HostInternal::Domain => {
                     if SchemeType::from(self.scheme()).is_special() {
                         assert!(!host_str.is_empty())
                     }
                 }
             }
             if self.path_start == self.host_end {
                 assert_eq!(self.port, None);
@@ -437,30 +488,60 @@ impl Url {
         self.slice(..self.scheme_end)
     }
 
     /// Return whether the URL has an 'authority',
     /// which can contain a username, password, host, and port number.
     ///
     /// URLs that do *not* are either path-only like `unix:/run/foo.socket`
     /// or cannot-be-a-base like `data:text/plain,Stuff`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("ftp://rms@example.com").unwrap();
+    /// assert!(url.has_authority());
+    ///
+    /// let url = Url::parse("unix:/run/foo.socket").unwrap();
+    /// assert!(!url.has_authority());
+    ///
+    /// let url = Url::parse("data:text/plain,Stuff").unwrap();
+    /// assert!(!url.has_authority());
+    /// ```
     #[inline]
     pub fn has_authority(&self) -> bool {
         debug_assert!(self.byte_at(self.scheme_end) == b':');
         self.slice(self.scheme_end..).starts_with("://")
     }
 
     /// Return whether this URL is a cannot-be-a-base URL,
     /// meaning that parsing a relative URL string with this URL as the base will return an error.
     ///
     /// This is the case if the scheme and `:` delimiter are not followed by a `/` slash,
     /// as is typically the case of `data:` and `mailto:` URLs.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("ftp://rms@example.com").unwrap();
+    /// assert!(!url.cannot_be_a_base());
+    ///
+    /// let url = Url::parse("unix:/run/foo.socket").unwrap();
+    /// assert!(!url.cannot_be_a_base());
+    ///
+    /// let url = Url::parse("data:text/plain,Stuff").unwrap();
+    /// assert!(url.cannot_be_a_base());
+    /// ```
     #[inline]
     pub fn cannot_be_a_base(&self) -> bool {
-        self.byte_at(self.path_start) != b'/'
+        !self.slice(self.path_start..).starts_with('/')
     }
 
     /// Return the username for this URL (typically the empty string)
     /// as a percent-encoded ASCII string.
     ///
     /// # Examples
     ///
     /// ```
@@ -509,74 +590,164 @@ impl Url {
             debug_assert!(self.byte_at(self.host_start - 1) == b'@');
             Some(self.slice(self.username_end + 1..self.host_start - 1))
         } else {
             None
         }
     }
 
     /// Equivalent to `url.host().is_some()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("ftp://rms@example.com").unwrap();
+    /// assert!(url.has_host());
+    ///
+    /// let url = Url::parse("unix:/run/foo.socket").unwrap();
+    /// assert!(!url.has_host());
+    ///
+    /// let url = Url::parse("data:text/plain,Stuff").unwrap();
+    /// assert!(!url.has_host());
+    /// ```
     pub fn has_host(&self) -> bool {
         !matches!(self.host, HostInternal::None)
     }
 
     /// Return the string representation of the host (domain or IP address) for this URL, if any.
     ///
     /// Non-ASCII domains are punycode-encoded per IDNA.
     /// IPv6 addresses are given between `[` and `]` brackets.
     ///
     /// Cannot-be-a-base URLs (typical of `data:` and `mailto:`) and some `file:` URLs
     /// don’t have a host.
     ///
     /// See also the `host` method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://127.0.0.1/index.html").unwrap();
+    /// assert_eq!(url.host_str(), Some("127.0.0.1"));
+    ///
+    /// let url = Url::parse("ftp://rms@example.com").unwrap();
+    /// assert_eq!(url.host_str(), Some("example.com"));
+    ///
+    /// let url = Url::parse("unix:/run/foo.socket").unwrap();
+    /// assert_eq!(url.host_str(), None);
+    ///
+    /// let url = Url::parse("data:text/plain,Stuff").unwrap();
+    /// assert_eq!(url.host_str(), None);
+    /// ```
     pub fn host_str(&self) -> Option<&str> {
         if self.has_host() {
             Some(self.slice(self.host_start..self.host_end))
         } else {
             None
         }
     }
 
     /// Return the parsed representation of the host for this URL.
     /// Non-ASCII domain labels are punycode-encoded per IDNA.
     ///
     /// Cannot-be-a-base URLs (typical of `data:` and `mailto:`) and some `file:` URLs
     /// don’t have a host.
     ///
     /// See also the `host_str` method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://127.0.0.1/index.html").unwrap();
+    /// assert!(url.host().is_some());
+    ///
+    /// let url = Url::parse("ftp://rms@example.com").unwrap();
+    /// assert!(url.host().is_some());
+    ///
+    /// let url = Url::parse("unix:/run/foo.socket").unwrap();
+    /// assert!(url.host().is_none());
+    ///
+    /// let url = Url::parse("data:text/plain,Stuff").unwrap();
+    /// assert!(url.host().is_none());
+    /// ```
     pub fn host(&self) -> Option<Host<&str>> {
         match self.host {
             HostInternal::None => None,
             HostInternal::Domain => Some(Host::Domain(self.slice(self.host_start..self.host_end))),
             HostInternal::Ipv4(address) => Some(Host::Ipv4(address)),
             HostInternal::Ipv6(address) => Some(Host::Ipv6(address)),
         }
     }
 
     /// If this URL has a host and it is a domain name (not an IP address), return it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://127.0.0.1/").unwrap();
+    /// assert_eq!(url.domain(), None);
+    ///
+    /// let url = Url::parse("https://example.com/").unwrap();
+    /// assert_eq!(url.domain(), Some("example.com"));
+    /// ```
     pub fn domain(&self) -> Option<&str> {
         match self.host {
             HostInternal::Domain => Some(self.slice(self.host_start..self.host_end)),
             _ => None,
         }
     }
 
     /// Return the port number for this URL, if any.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("https://example.com").unwrap();
+    /// assert_eq!(url.port(), None);
+    ///
+    /// let url = Url::parse("ssh://example.com:22").unwrap();
+    /// assert_eq!(url.port(), Some(22));
+    /// ```
     #[inline]
     pub fn port(&self) -> Option<u16> {
         self.port
     }
 
     /// Return the port number for this URL, or the default port number if it is known.
     ///
     /// This method only knows the default port number
     /// of the `http`, `https`, `ws`, `wss`, `ftp`, and `gopher` schemes.
     ///
     /// For URLs in these schemes, this method always returns `Some(_)`.
     /// For other schemes, it is the same as `Url::port()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let url = Url::parse("foo://example.com").unwrap();
+    /// assert_eq!(url.port_or_known_default(), None);
+    ///
+    /// let url = Url::parse("foo://example.com:1456").unwrap();
+    /// assert_eq!(url.port_or_known_default(), Some(1456));
+    ///
+    /// let url = Url::parse("https://example.com").unwrap();
+    /// assert_eq!(url.port_or_known_default(), Some(443));
+    /// ```
     #[inline]
     pub fn port_or_known_default(&self) -> Option<u16> {
         self.port.or_else(|| parser::default_port(self.scheme()))
     }
 
     /// If the URL has a host, return something that implements `ToSocketAddrs`.
     ///
     /// If the URL has no port number and the scheme’s default port number is not known
@@ -757,17 +928,17 @@ impl Url {
     ///
     /// url.query_pairs_mut().append_pair("foo", "bar");
     /// assert_eq!(url.query(), Some("lang=fr&foo=bar"));
     /// assert_eq!(url.as_str(), "https://example.net/?lang=fr&foo=bar#nav");
     ///
     /// url.query_pairs_mut()
     ///     .clear()
     ///     .append_pair("foo", "bar & baz")
-    ///     .append_pair("saisons", "Été+hiver");
+    ///     .append_pair("saisons", "\u{00C9}t\u{00E9}+hiver");
     /// assert_eq!(url.query(), Some("foo=bar+%26+baz&saisons=%C3%89t%C3%A9%2Bhiver"));
     /// assert_eq!(url.as_str(),
     ///            "https://example.net/?foo=bar+%26+baz&saisons=%C3%89t%C3%A9%2Bhiver#nav");
     /// ```
     ///
     /// Note: `url.query_pairs_mut().clear();` is equivalent to `url.set_query(Some(""))`,
     /// not `url.set_query(None)`.
     ///
@@ -819,17 +990,17 @@ impl Url {
                 parser.parse_path_start(scheme_type, &mut has_host, parser::Input::new(path));
             }
         });
         self.restore_after_path(old_after_path_pos, &after_path);
     }
 
     /// Return an object with methods to manipulate this URL’s path segments.
     ///
-    /// Return `Err(())` if this URl is cannot-be-a-base.
+    /// Return `Err(())` if this URL is cannot-be-a-base.
     pub fn path_segments_mut(&mut self) -> Result<PathSegmentsMut, ()> {
         if self.cannot_be_a_base() {
             Err(())
         } else {
             Ok(path_segments::new(self))
         }
     }
 
@@ -843,16 +1014,30 @@ impl Url {
         if let Some(ref mut index) = self.fragment_start { adjust(index) }
         self.serialization.push_str(after_path)
     }
 
     /// Change this URL’s port number.
     ///
     /// If this URL is cannot-be-a-base, does not have a host, or has the `file` scheme;
     /// do nothing and return `Err`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use url::Url;
+    ///
+    /// let mut url = Url::parse("ssh://example.net:2048/").unwrap();
+    ///
+    /// url.set_port(Some(4096)).unwrap();
+    /// assert_eq!(url.as_str(), "ssh://example.net:4096/");
+    ///
+    /// url.set_port(None).unwrap();
+    /// assert_eq!(url.as_str(), "ssh://example.net/");
+    /// ```
     pub fn set_port(&mut self, mut port: Option<u16>) -> Result<(), ()> {
         if !self.has_host() || self.scheme() == "file" {
             return Err(())
         }
         if port.is_some() && port == parser::default_port(self.scheme()) {
             port = None
         }
         self.set_port_internal(port);
@@ -897,22 +1082,28 @@ impl Url {
     /// Removing the host (calling this with `None`)
     /// will also remove any username, password, and port number.
     pub fn set_host(&mut self, host: Option<&str>) -> Result<(), ParseError> {
         if self.cannot_be_a_base() {
             return Err(ParseError::SetHostOnCannotBeABaseUrl)
         }
 
         if let Some(host) = host {
+            if host == "" && SchemeType::from(self.scheme()).is_special() {
+                return Err(ParseError::EmptyHost);
+            }
             self.set_host_internal(try!(Host::parse(host)), None)
         } else if self.has_host() {
+            if SchemeType::from(self.scheme()).is_special() {
+                return Err(ParseError::EmptyHost)
+            }
             debug_assert!(self.byte_at(self.scheme_end) == b':');
             debug_assert!(self.byte_at(self.path_start) == b'/');
             let new_path_start = self.scheme_end + 1;
-            self.serialization.drain(self.path_start as usize..new_path_start as usize);
+            self.serialization.drain(new_path_start as usize..self.path_start as usize);
             let offset = self.path_start - new_path_start;
             self.path_start = new_path_start;
             self.username_end = new_path_start;
             self.host_start = new_path_start;
             self.host_end = new_path_start;
             self.port = None;
             if let Some(ref mut index) = self.query_start { *index -= offset }
             if let Some(ref mut index) = self.fragment_start { *index -= offset }
@@ -1327,17 +1518,17 @@ impl serde::Serialize for Url {
 #[cfg(feature="serde")]
 impl serde::Deserialize for Url {
     fn deserialize<D>(deserializer: &mut D) -> Result<Url, D::Error> where D: serde::Deserializer {
         let string_representation: String = try!(serde::Deserialize::deserialize(deserializer));
         Ok(Url::parse(&string_representation).unwrap())
     }
 }
 
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "redox"))]
 fn path_to_file_url_segments(path: &Path, serialization: &mut String) -> Result<(), ()> {
     use std::os::unix::prelude::OsStrExt;
     if !path.is_absolute() {
         return Err(())
     }
     let mut empty = true;
     // skip the root component
     for component in path.components().skip(1) {
@@ -1387,17 +1578,17 @@ fn path_to_file_url_segments_windows(pat
         // FIXME: somehow work with non-unicode?
         let component = try!(component.as_os_str().to_str().ok_or(()));
         serialization.push('/');
         serialization.extend(percent_encode(component.as_bytes(), PATH_SEGMENT_ENCODE_SET));
     }
     Ok(())
 }
 
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "redox"))]
 fn file_url_segments_to_pathbuf(segments: str::Split<char>) -> Result<PathBuf, ()> {
     use std::ffi::OsStr;
     use std::os::unix::prelude::OsStrExt;
     use std::path::PathBuf;
 
     let mut bytes = Vec::new();
     for segment in segments {
         bytes.push(b'/');
@@ -1414,21 +1605,41 @@ fn file_url_segments_to_pathbuf(segments
 fn file_url_segments_to_pathbuf(segments: str::Split<char>) -> Result<PathBuf, ()> {
     file_url_segments_to_pathbuf_windows(segments)
 }
 
 // Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
 #[cfg_attr(not(windows), allow(dead_code))]
 fn file_url_segments_to_pathbuf_windows(mut segments: str::Split<char>) -> Result<PathBuf, ()> {
     let first = try!(segments.next().ok_or(()));
-    if first.len() != 2 || !first.starts_with(parser::ascii_alpha)
-            || first.as_bytes()[1] != b':' {
-        return Err(())
-    }
-    let mut string = first.to_owned();
+
+    let mut string = match first.len() {
+        2 => {
+            if !first.starts_with(parser::ascii_alpha) || first.as_bytes()[1] != b':' {
+                return Err(())
+            }
+
+            first.to_owned()
+        },
+
+        4 => {
+            if !first.starts_with(parser::ascii_alpha) {
+                return Err(())
+            }
+            let bytes = first.as_bytes();
+            if bytes[1] != b'%' || bytes[2] != b'3' || (bytes[3] != b'a' && bytes[3] != b'A') {
+                return Err(())
+            }
+
+            first[0..1].to_owned() + ":"
+        },
+
+        _ => return Err(()),
+    };
+
     for segment in segments {
         string.push('\\');
 
         // Currently non-unicode windows paths cannot be represented
         match String::from_utf8(percent_decode(segment.as_bytes()).collect()) {
             Ok(s) => string.push_str(&s),
             Err(..) => return Err(()),
         }
--- a/third_party/rust/url/src/parser.rs
+++ b/third_party/rust/url/src/parser.rs
@@ -1078,22 +1078,23 @@ impl<'a> Parser<'a> {
         Ok(Url {
             serialization: self.serialization,
             fragment_start: Some(try!(to_u32(before_fragment.len()))),
             ..*base_url
         })
     }
 
     pub fn parse_fragment(&mut self, mut input: Input) {
-        while let Some(c) = input.next() {
+        while let Some((c, utf8_c)) = input.next_utf8() {
             if c ==  '\0' {
                 self.syntax_violation("NULL characters are ignored in URL fragment identifiers")
             } else {
                 self.check_url_code_point(c, &input);
-                self.serialization.push(c);  // No percent-encoding here.
+                self.serialization.extend(utf8_percent_encode(utf8_c,
+                                                              SIMPLE_ENCODE_SET));
             }
         }
     }
 
     fn check_url_code_point(&self, c: char, input: &Input) {
         if let Some(log) = self.log_syntax_violation {
             if c == '%' {
                 let mut input = input.clone();
--- a/third_party/rust/url/tests/setters_tests.json
+++ b/third_party/rust/url/tests/setters_tests.json
@@ -1122,27 +1122,27 @@
             "href": "https://example.net?lang=en-US#nav",
             "new_value": "",
             "expected": {
                 "href": "https://example.net/?lang=en-US",
                 "hash": ""
             }
         },
         {
-            "comment": "No percent-encoding at all (!); nuls, tabs, and newlines are removed. Leading or training C0 controls and space are removed.",
+            "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed",
             "href": "a:/",
             "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
             "expected": {
-                "href": "a:/#!\u0001\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
-                "hash": "#!\u0001\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé"
+                "href": "a:/#!%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
+                "hash": "#!%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
             }
         },
         {
             "comment": "Bytes already percent-encoded are left as-is",
             "href": "http://example.net",
             "new_value": "%c3%89té",
             "expected": {
-                "href": "http://example.net/#%c3%89té",
-                "hash": "#%c3%89té"
+                "href": "http://example.net/#%c3%89t%C3%A9",
+                "hash": "#%c3%89t%C3%A9"
             }
         }
     ]
 }
--- a/third_party/rust/url/tests/unit.rs
+++ b/third_party/rust/url/tests/unit.rs
@@ -10,16 +10,22 @@
 
 extern crate url;
 
 use std::borrow::Cow;
 use std::net::{Ipv4Addr, Ipv6Addr};
 use std::path::{Path, PathBuf};
 use url::{Host, Url, form_urlencoded};
 
+#[test]
+fn size() {
+    use std::mem::size_of;
+    assert_eq!(size_of::<Url>(), size_of::<Option<Url>>());
+}
+
 macro_rules! assert_from_file_path {
     ($path: expr) => { assert_from_file_path!($path, $path) };
     ($path: expr, $url_path: expr) => {{
         let url = Url::from_file_path(Path::new($path)).unwrap();
         assert_eq!(url.host(), None);
         assert_eq!(url.path(), $url_path);
         assert_eq!(url.to_file_path(), Ok(PathBuf::from($path)));
     }};
@@ -65,16 +71,20 @@ fn new_path_windows_fun() {
         assert_from_file_path!("C:\\foo\\ba\0r", "/C:/foo/ba%00r");
 
         // Invalid UTF-8
         assert!(Url::parse("file:///C:/foo/ba%80r").unwrap().to_file_path().is_err());
 
         // test windows canonicalized path
         let path = PathBuf::from(r"\\?\C:\foo\bar");
         assert!(Url::from_file_path(path).is_ok());
+
+        // Percent-encoded drive letter
+        let url = Url::parse("file:///C%3A/foo/bar").unwrap();
+        assert_eq!(url.to_file_path(), Ok(PathBuf::from(r"C:\foo\bar")));
     }
 }
 
 
 #[test]
 fn new_directory_paths() {
     if cfg!(unix) {
         assert_eq!(Url::from_directory_path(Path::new("relative")), Err(()));
@@ -187,16 +197,17 @@ fn host_serialization() {
     assert_eq!(Url::parse("http://[0::2]").unwrap().host_str(), Some("[::2]"));
     assert_eq!(Url::parse("http://[0::ffff:0:2]").unwrap().host_str(), Some("[::ffff:0:2]"));
 }
 
 #[test]
 fn test_idna() {
     assert!("http://goșu.ro".parse::<Url>().is_ok());
     assert_eq!(Url::parse("http://☃.net/").unwrap().host(), Some(Host::Domain("xn--n3h.net")));
+    assert!("https://r2---sn-huoa-cvhl.googlevideo.com/crossdomain.xml".parse::<Url>().is_ok());
 }
 
 #[test]
 fn test_serialization() {
     let data = [
         ("http://example.com/", "http://example.com/"),
         ("http://addslash.com", "http://addslash.com/"),
         ("http://@emptyuser.com/", "http://emptyuser.com/"),
@@ -266,16 +277,21 @@ fn issue_61() {
 fn issue_197() {
     let mut url = Url::from_file_path("/").expect("Failed to parse path");
     url.assert_invariants();
     assert_eq!(url, Url::parse("file:///").expect("Failed to parse path + protocol"));
     url.path_segments_mut().expect("path_segments_mut").pop_if_empty();
 }
 
 #[test]
+fn issue_241() {
+    Url::parse("mailto:").unwrap().cannot_be_a_base();
+}
+
+#[test]
 /// https://github.com/servo/rust-url/issues/222
 fn append_trailing_slash() {
     let mut url: Url = "http://localhost:6767/foo/bar?a=b".parse().unwrap();
     url.assert_invariants();
     url.path_segments_mut().unwrap().push("");
     url.assert_invariants();
     assert_eq!(url.to_string(), "http://localhost:6767/foo/bar/?a=b");
 }
@@ -296,8 +312,24 @@ fn extend_query_pairs_then_mutate() {
 /// https://github.com/servo/rust-url/issues/222
 fn append_empty_segment_then_mutate() {
     let mut url: Url = "http://localhost:6767/foo/bar?a=b".parse().unwrap();
     url.assert_invariants();
     url.path_segments_mut().unwrap().push("").pop();
     url.assert_invariants();
     assert_eq!(url.to_string(), "http://localhost:6767/foo/bar?a=b");
 }
+
+#[test]
+/// https://github.com/servo/rust-url/issues/243
+fn test_set_host() {
+    let mut url = Url::parse("https://example.net/hello").unwrap();
+    url.set_host(Some("foo.com")).unwrap();
+    assert_eq!(url.as_str(), "https://foo.com/hello");
+    assert!(url.set_host(None).is_err());
+    assert_eq!(url.as_str(), "https://foo.com/hello");
+    assert!(url.set_host(Some("")).is_err());
+    assert_eq!(url.as_str(), "https://foo.com/hello");
+
+    let mut url = Url::parse("foobar://example.net/hello").unwrap();
+    url.set_host(None).unwrap();
+    assert_eq!(url.as_str(), "foobar:/hello");
+}
--- a/third_party/rust/url/tests/urltestdata.json
+++ b/third_party/rust/url/tests/urltestdata.json
@@ -836,16 +836,46 @@
     "host": "[2001::1]",
     "hostname": "[2001::1]",
     "port": "",
     "pathname": "/",
     "search": "",
     "hash": ""
   },
   {
+    "input": "http://[::127.0.0.1]",
+    "base": "http://example.org/foo/bar",
+    "href": "http://[::7f00:1]/",
+    "origin": "http://[::7f00:1]",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "[::7f00:1]",
+    "hostname": "[::7f00:1]",
+    "port": "",
+    "pathname": "/",
+    "search": "",
+    "hash": ""
+  },
+  {
+    "input": "http://[0:0:0:0:0:0:13.1.68.3]",
+    "base": "http://example.org/foo/bar",
+    "href": "http://[::d01:4403]/",
+    "origin": "http://[::d01:4403]",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "[::d01:4403]",
+    "hostname": "[::d01:4403]",
+    "port": "",
+    "pathname": "/",
+    "search": "",
+    "hash": ""
+  },
+  {
     "input": "http://[2001::1]:80",
     "base": "http://example.org/foo/bar",
     "href": "http://[2001::1]/",
     "origin": "http://[2001::1]",
     "protocol": "http:",
     "username": "",
     "password": "",
     "host": "[2001::1]",
@@ -1257,43 +1287,58 @@
     "port": "",
     "pathname": "/a/%2f/c",
     "search": "",
     "hash": ""
   },
   {
     "input": "#β",
     "base": "http://example.org/foo/bar",
-    "href": "http://example.org/foo/bar#β",
+    "href": "http://example.org/foo/bar#%CE%B2",
     "origin": "http://example.org",
     "protocol": "http:",
     "username": "",
     "password": "",
     "host": "example.org",
     "hostname": "example.org",
     "port": "",
     "pathname": "/foo/bar",
     "search": "",
-    "hash": "#β"
+    "hash": "#%CE%B2"
   },
   {
     "input": "data:text/html,test#test",
     "base": "http://example.org/foo/bar",
     "href": "data:text/html,test#test",
     "origin": "null",
     "protocol": "data:",
     "username": "",
     "password": "",
     "host": "",
     "hostname": "",
     "port": "",
     "pathname": "text/html,test",
     "search": "",
     "hash": "#test"
   },
+  {
+    "input": "tel:1234567890",
+    "base": "http://example.org/foo/bar",
+    "href": "tel:1234567890",
+    "origin": "null",
+    "protocol": "tel:",
+    "username": "",
+    "password": "",
+    "host": "",
+    "hostname": "",
+    "port": "",
+    "pathname": "1234567890",
+    "search": "",
+    "hash": ""
+  },
   "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html",
   {
     "input": "file:c:\\foo\\bar.html",
     "base": "file:///tmp/mock/path",
     "href": "file:///c:/foo/bar.html",
     "protocol": "file:",
     "username": "",
     "password": "",
@@ -2111,42 +2156,42 @@
     "port": "",
     "pathname": "/foo",
     "search": "?bar=baz",
     "hash": ""
   },
   {
     "input": "http://www.google.com/foo?bar=baz# »",
     "base": "about:blank",
-    "href": "http://www.google.com/foo?bar=baz# »",
+    "href": "http://www.google.com/foo?bar=baz# %C2%BB",
     "origin": "http://www.google.com",
     "protocol": "http:",
     "username": "",
     "password": "",
     "host": "www.google.com",
     "hostname": "www.google.com",
     "port": "",
     "pathname": "/foo",
     "search": "?bar=baz",
-    "hash": "# »"
+    "hash": "# %C2%BB"
   },
   {
     "input": "data:test# »",
     "base": "about:blank",
-    "href": "data:test# »",
+    "href": "data:test# %C2%BB",
     "origin": "null",
     "protocol": "data:",
     "username": "",
     "password": "",
     "host": "",
     "hostname": "",
     "port": "",
     "pathname": "test",
     "search": "",
-    "hash": "# »"
+    "hash": "# %C2%BB"
   },
   {
     "input": "http://[www.google.com]/",
     "base": "about:blank",
     "failure": true
   },
   {
     "input": "http://www.google.com",
@@ -4268,10 +4313,65 @@
     "password": "",
     "host": "example.org",
     "hostname": "example.org",
     "port": "",
     "pathname": "/foo/bar",
     "search": "??a=b&c=d",
     "searchParams": "%3Fa=b&c=d",
     "hash": ""
+  },
+  "# Scheme only",
+  {
+    "input": "http:",
+    "base": "http://example.org/foo/bar",
+    "href": "http://example.org/foo/bar",
+    "origin": "http://example.org",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "example.org",
+    "hostname": "example.org",
+    "port": "",
+    "pathname": "/foo/bar",
+    "search": "",
+    "searchParams": "",
+    "hash": ""
+  },
+  {
+    "input": "http:",
+    "base": "https://example.org/foo/bar",
+    "failure": true
+  },
+  {
+    "input": "sc:",
+    "base": "https://example.org/foo/bar",
+    "href": "sc:",
+    "origin": "null",
+    "protocol": "sc:",
+    "username": "",
+    "password": "",
+    "host": "",
+    "hostname": "",
+    "port": "",
+    "pathname": "",
+    "search": "",
+    "searchParams": "",
+    "hash": ""
+  },
+  "# Percent encoding of fragments",
+  {
+    "input": "http://foo.bar/baz?qux#foo\bbar",
+    "base": "about:blank",
+    "href": "http://foo.bar/baz?qux#foo%08bar",
+    "origin": "http://foo.bar",
+    "protocol": "http:",
+    "username": "",
+    "password": "",
+    "host": "foo.bar",
+    "hostname": "foo.bar",
+    "port": "",
+    "pathname": "/baz",
+    "search": "?qux",
+    "searchParams": "",
+    "hash": "#foo%08bar"
   }
 ]
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -72,17 +72,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "rust_url_capi"
 version = "0.0.1"
 dependencies = [
  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring 0.1.0",
- "url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "unicode-bidi"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -90,23 +90,23 @@ dependencies = [
 
 [[package]]
 name = "unicode-normalization"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "url"
-version = "1.2.1"
+version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [metadata]
 "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
 "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
 "checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
 "checksum matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc3ad8109fa4b522f9b0cd81440422781f564aaf8c195de6b9d6642177ad0dd"
 "checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
 "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
-"checksum url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8527c62d9869a08325c38272b3f85668df22a65890c61a639d233dc0ed0b23a2"
+"checksum url 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f024e241a55f5c88401595adc1d4af0c9649e91da82d0e190fe55950231ae575"
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -59,17 +59,17 @@ name = "nsstring"
 version = "0.1.0"
 
 [[package]]
 name = "rust_url_capi"
 version = "0.0.1"
 dependencies = [
  "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring 0.1.0",
- "url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "unicode-bidi"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -77,23 +77,23 @@ dependencies = [
 
 [[package]]
 name = "unicode-normalization"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "url"
-version = "1.2.1"
+version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [metadata]
 "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
 "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
 "checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
 "checksum matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc3ad8109fa4b522f9b0cd81440422781f564aaf8c195de6b9d6642177ad0dd"
 "checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
 "checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
-"checksum url 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8527c62d9869a08325c38272b3f85668df22a65890c61a639d233dc0ed0b23a2"
+"checksum url 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f024e241a55f5c88401595adc1d4af0c9649e91da82d0e190fe55950231ae575"