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