import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +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"}

0
third_party/rust/url/.cargo-ok vendored Normal file
View file

3
third_party/rust/url/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
target
Cargo.lock
/.cargo/config

8
third_party/rust/url/.travis.yml vendored Normal file
View file

@ -0,0 +1,8 @@
language: rust
rust:
- nightly
- beta
- stable
script: make test
notifications:
webhooks: http://build.servo.org:54856/travis

38
third_party/rust/url/Cargo.toml vendored Normal file
View file

@ -0,0 +1,38 @@
[package]
name = "url"
version = "1.2.1"
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"
[[test]]
name = "unit"
[[test]]
name = "data"
harness = false
[lib]
test = false
[dev-dependencies]
rustc-test = "0.1"
rustc-serialize = "0.3"
[features]
query_encoding = ["encoding"]
heap_size = ["heapsize"]
[dependencies]
encoding = {version = "0.2", optional = true}
heapsize = {version = ">=0.1.1, <0.4", optional = true}
idna = { version = "0.1.0", path = "./idna" }
matches = "0.1"
rustc-serialize = {version = "0.3", optional = true}
serde = {version = ">=0.6.1, <0.9", optional = true}

201
third_party/rust/url/LICENSE-APACHE vendored Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

25
third_party/rust/url/LICENSE-MIT vendored Normal file
View file

@ -0,0 +1,25 @@
Copyright (c) 2013-2016 The rust-url developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

5
third_party/rust/url/Makefile vendored Normal file
View file

@ -0,0 +1,5 @@
test:
cargo test --features "query_encoding serde rustc-serialize"
[ x$$TRAVIS_RUST_VERSION != xnightly ] || cargo test --features heapsize
.PHONY: test

10
third_party/rust/url/README.md vendored Normal file
View file

@ -0,0 +1,10 @@
rust-url
========
[![Travis build Status](https://travis-ci.org/servo/rust-url.svg?branch=master)](https://travis-ci.org/servo/rust-url) [![Appveyor build status](https://ci.appveyor.com/api/projects/status/ulkqx2xcemyod6xa?svg=true)](https://ci.appveyor.com/project/Manishearth/rust-url)
URL library for Rust, based on the [URL Standard](https://url.spec.whatwg.org/).
[Documentation](https://docs.rs/url/)
Please see [UPGRADING.md](https://github.com/servo/rust-url/blob/master/UPGRADING.md) if you are upgrading from 0.x to 1.x.

263
third_party/rust/url/UPGRADING.md vendored Normal file
View file

@ -0,0 +1,263 @@
# Guide to upgrading from url 0.x to 1.x
* The fields of `Url` are now private because the `Url` constructor, parser,
and setters maintain invariants that could be violated if you were to set the fields directly.
Instead of accessing, for example, `url.scheme`, use the getter method, such as `url.scheme()`.
Instead of assigning directly to a field, for example `url.scheme = "https".to_string()`,
use the setter method, such as `url.set_scheme("https").unwrap()`.
(Some setters validate the new value and return a `Result` that must be used).
* The methods of `Url` now return `&str` instead of `String`,
thus reducing allocations and making serialization cheap.
* The `path()` method on `url::Url` instances used to return `Option<&[String]>`;
now it returns `&str`.
If you would like functionality more similar to the old behavior of `path()`,
use `path_segments()` that returns `Option<str::Split<char>>`.
Before upgrading:
```rust
let issue_list_url = Url::parse(
"https://github.com/rust-lang/rust/issues?labels=E-easy&state=open"
).unwrap();
assert_eq!(issue_list_url.path(), Some(&["rust-lang".to_string(),
"rust".to_string(),
"issues".to_string()][..]));
```
After upgrading:
```rust
let issue_list_url = Url::parse(
"https://github.com/rust-lang/rust/issues?labels=E-easy&state=open"
).unwrap();
assert_eq!(issue_list_url.path(), "/rust-lang/rust/issues");
assert_eq!(issue_list_url.path_segments().map(|c| c.collect::<Vec<_>>()),
Some(vec!["rust-lang", "rust", "issues"]));
```
* The `path_mut()` method on `url::Url` instances that allowed modification of a URL's path
has been replaced by `path_segments_mut()`.
Before upgrading:
```rust
let mut url = Url::parse("https://github.com/rust-lang/rust").unwrap();
url.path_mut().unwrap().push("issues");
```
After upgrading:
```rust
let mut url = Url::parse("https://github.com/rust-lang/rust").unwrap();
url.path_segments_mut().unwrap().push("issues");
```
* The `domain_mut()` method on `url::Url` instances that allowed modification of a URL's domain
has been replaced by `set_host()` and `set_ip_host()`.
* The `host()` method on `url::Url` instances used to return `Option<&Host>`;
now it returns `Option<Host<&str>>`.
The `serialize_host()` method that returned `Option<String>`
has been replaced by the `host_str()` method that returns `Option<&str>`.
* The `serialize()` method on `url::Url` instances that returned `String`
has been replaced by an `as_str()` method that returns `&str`.
Before upgrading:
```rust
let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap();
assert_eq!(this_document.serialize(), "http://servo.github.io/rust-url/url/index.html".to_string());
```
After upgrading:
```rust
let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap();
assert_eq!(this_document.as_str(), "http://servo.github.io/rust-url/url/index.html");
```
* `url::UrlParser` has been replaced by `url::Url::parse()` and `url::Url::join()`.
Before upgrading:
```rust
let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap();
let css_url = UrlParser::new().base_url(&this_document).parse("../main.css").unwrap();
assert_eq!(css_url.serialize(), "http://servo.github.io/rust-url/main.css".to_string());
```
After upgrading:
```rust
let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap();
let css_url = this_document.join("../main.css").unwrap();
assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css");
```
* `url::parse_path()` and `url::UrlParser::parse_path()` have been removed without replacement.
As a workaround, you can give a base URL that you then ignore too `url::Url::parse()`.
Before upgrading:
```rust
let (path, query, fragment) = url::parse_path("/foo/bar/../baz?q=42").unwrap();
assert_eq!(path, vec!["foo".to_string(), "baz".to_string()]);
assert_eq!(query, Some("q=42".to_string()));
assert_eq!(fragment, None);
```
After upgrading:
```rust
let base = Url::parse("http://example.com").unwrap();
let with_path = base.join("/foo/bar/../baz?q=42").unwrap();
assert_eq!(with_path.path(), "/foo/baz");
assert_eq!(with_path.query(), Some("q=42"));
assert_eq!(with_path.fragment(), None);
```
* The `url::form_urlencoded::serialize()` method
has been replaced with the `url::form_urlencoded::Serializer` struct.
Instead of calling `serialize()` with key/value pairs,
create a new `Serializer` with a new string,
call the `extend_pairs()` method on the `Serializer` instance with the key/value pairs as the argument,
then call `finish()`.
Before upgrading:
```rust
let form = url::form_urlencoded::serialize(form.iter().map(|(k, v)| {
(&k[..], &v[..])
}));
```
After upgrading:
```rust
let form = url::form_urlencoded::Serializer::new(String::new()).extend_pairs(
form.iter().map(|(k, v)| { (&k[..], &v[..]) })
).finish();
```
* The `set_query_from_pairs()` method on `url::Url` instances that took key/value pairs
has been replaced with `query_pairs_mut()`, which allows you to modify the `url::Url`'s query pairs.
Before upgrading:
```rust
let mut url = Url::parse("https://duckduckgo.com/").unwrap();
let pairs = vec![
("q", "test"),
("ia", "images"),
];
url.set_query_from_pairs(pairs.iter().map(|&(k, v)| {
(&k[..], &v[..])
}));
```
After upgrading:
```rust
let mut url = Url::parse("https://duckduckgo.com/").unwrap();
let pairs = vec![
("q", "test"),
("ia", "images"),
];
url.query_pairs_mut().clear().extend_pairs(
pairs.iter().map(|&(k, v)| { (&k[..], &v[..]) })
);
```
* `url::SchemeData`, its variants `Relative` and `NonRelative`,
and the struct `url::RelativeSchemeData` have been removed.
Instead of matching on these variants
to determine if you have a URL in a relative scheme such as HTTP
versus a URL in a non-relative scheme as data,
use the `cannot_be_a_base()` method to determine which kind you have.
Before upgrading:
```rust
match url.scheme_data {
url::SchemeData::Relative(..) => {}
url::SchemeData::NonRelative(..) => {
return Err(human(format!("`{}` must have relative scheme \
data: {}", field, url)))
}
}
```
After upgrading:
```rust
if url.cannot_be_a_base() {
return Err(human(format!("`{}` must have relative scheme \
data: {}", field, url)))
}
```
* The functions `url::whatwg_scheme_type_mapper()`, the `SchemeType` enum,
and the `scheme_type_mapper()` method on `url::UrlParser` instances have been removed.
`SchemeType` had a method for getting the `default_port()`;
to replicate this functionality, use the method `port_or_known_default()` on `url::Url` instances.
The `port_or_default()` method on `url::Url` instances has been removed;
use `port_or_known_default()` instead.
Before upgrading:
```rust
let port = match whatwg_scheme_type_mapper(&url.scheme) {
SchemeType::Relative(port) => port,
_ => return Err(format!("Invalid special scheme: `{}`",
raw_url.scheme)),
};
```
After upgrading:
```rust
let port = match url.port_or_known_default() {
Some(port) => port,
_ => return Err(format!("Invalid special scheme: `{}`",
url.scheme())),
};
```
* The following formatting utilities have been removed without replacement;
look at their linked previous implementations
if you would like to replicate the functionality in your code:
* [`url::format::PathFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL24)
* [`url::format::UserInfoFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL50)
* [`url::format::UrlNoFragmentFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL70)
* `url::percent_encoding::percent_decode()` used to have a return type of `Vec<u8>`;
now it returns an iterator of decoded `u8` bytes that also implements `Into<Cow<u8>>`.
Use `.into().to_owned()` to obtain a `Vec<u8>`.
(`.collect()` also works but might not be as efficient.)
* The `url::percent_encoding::EncodeSet` struct and constant instances
used with `url::percent_encoding::percent_encode()`
have been changed to structs that implement the trait `url::percent_encoding::EncodeSet`.
* `SIMPLE_ENCODE_SET`, `QUERY_ENCODE_SET`, `DEFAULT_ENCODE_SET`,
and `USERINFO_ENCODE_SET` have the same behavior.
* `USERNAME_ENCODE_SET` and `PASSWORD_ENCODE_SET` have been removed;
use `USERINFO_ENCODE_SET` instead.
* `HTTP_VALUE_ENCODE_SET` has been removed;
an implementation of it in the new types can be found [in hyper's source](
https://github.com/hyperium/hyper/blob/67436c5bf615cf5a55a71e32b788afef5985570e/src/header/parsing.rs#L131-L138)
if you need to replicate this functionality in your code.
* `FORM_URLENCODED_ENCODE_SET` has been removed;
instead, use the functionality in `url::form_urlencoded`.
* `PATH_SEGMENT_ENCODE_SET` has been added for use on '/'-separated path segments.
* `url::percent_encoding::percent_decode_to()` has been removed.
Use `url::percent_encoding::percent_decode()` which returns an iterator.
You can then use the iterator’s `collect()` method
or give it to some data structure’s `extend()` method.
* A number of `ParseError` variants have changed.
[See the documentation for the current set](http://servo.github.io/rust-url/url/enum.ParseError.html).
* `url::OpaqueOrigin::new()` and `url::Origin::UID(OpaqueOrigin)`
have been replaced by `url::Origin::new_opaque()` and `url::Origin::Opaque(OpaqueOrigin)`, respectively.

13
third_party/rust/url/appveyor.yml vendored Normal file
View file

@ -0,0 +1,13 @@
install:
- ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe'
- rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- rustc -V
- cargo -V
- git submodule update --init --recursive
build: false
test_script:
- cargo build
- cargo test --verbose

0
third_party/rust/url/docs/.nojekyll vendored Normal file
View file

3
third_party/rust/url/docs/404.html vendored Normal file
View file

@ -0,0 +1,3 @@
<meta http-equiv="refresh" content="0; url=https://docs.rs/url/">
<link rel="canonical" href="https://docs.rs/url/">
<a href="https://docs.rs/url/">Moved to docs.rs</a>

3
third_party/rust/url/docs/index.html vendored Normal file
View file

@ -0,0 +1,3 @@
<meta http-equiv="refresh" content="0; url=https://docs.rs/url/">
<link rel="canonical" href="https://docs.rs/url/">
<a href="https://docs.rs/url/">Moved to docs.rs</a>

BIN
third_party/rust/url/github.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

14
third_party/rust/url/rust-url-todo vendored Normal file
View file

@ -0,0 +1,14 @@
* 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");
}

135
third_party/rust/url/src/encoding.rs vendored Normal file
View file

@ -0,0 +1,135 @@
// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Abstraction that conditionally compiles either to rust-encoding,
//! or to only support UTF-8.
#[cfg(feature = "query_encoding")] extern crate encoding;
use std::borrow::Cow;
#[cfg(feature = "query_encoding")] use self::encoding::types::{DecoderTrap, EncoderTrap};
#[cfg(feature = "query_encoding")] use self::encoding::label::encoding_from_whatwg_label;
#[cfg(feature = "query_encoding")] pub use self::encoding::types::EncodingRef;
#[cfg(feature = "query_encoding")]
#[derive(Copy, Clone)]
pub struct EncodingOverride {
/// `None` means UTF-8.
encoding: Option<EncodingRef>
}
#[cfg(feature = "query_encoding")]
impl EncodingOverride {
pub fn from_opt_encoding(encoding: Option<EncodingRef>) -> Self {
encoding.map(Self::from_encoding).unwrap_or_else(Self::utf8)
}
pub fn from_encoding(encoding: EncodingRef) -> Self {
EncodingOverride {
encoding: if encoding.name() == "utf-8" { None } else { Some(encoding) }
}
}
#[inline]
pub fn utf8() -> Self {
EncodingOverride { encoding: None }
}
pub fn lookup(label: &[u8]) -> Option<Self> {
// Don't use String::from_utf8_lossy since no encoding label contains U+FFFD
// https://encoding.spec.whatwg.org/#names-and-labels
::std::str::from_utf8(label)
.ok()
.and_then(encoding_from_whatwg_label)
.map(Self::from_encoding)
}
/// https://encoding.spec.whatwg.org/#get-an-output-encoding
pub fn to_output_encoding(self) -> Self {
if let Some(encoding) = self.encoding {
if matches!(encoding.name(), "utf-16le" | "utf-16be") {
return Self::utf8()
}
}
self
}
pub fn is_utf8(&self) -> bool {
self.encoding.is_none()
}
pub fn name(&self) -> &'static str {
match self.encoding {
Some(encoding) => encoding.name(),
None => "utf-8",
}
}
pub fn decode<'a>(&self, input: Cow<'a, [u8]>) -> Cow<'a, str> {
match self.encoding {
// `encoding.decode` never returns `Err` when called with `DecoderTrap::Replace`
Some(encoding) => encoding.decode(&input, DecoderTrap::Replace).unwrap().into(),
None => decode_utf8_lossy(input),
}
}
pub fn encode<'a>(&self, input: Cow<'a, str>) -> Cow<'a, [u8]> {
match self.encoding {
// `encoding.encode` never returns `Err` when called with `EncoderTrap::NcrEscape`
Some(encoding) => Cow::Owned(encoding.encode(&input, EncoderTrap::NcrEscape).unwrap()),
None => encode_utf8(input)
}
}
}
#[cfg(not(feature = "query_encoding"))]
#[derive(Copy, Clone)]
pub struct EncodingOverride;
#[cfg(not(feature = "query_encoding"))]
impl EncodingOverride {
#[inline]
pub fn utf8() -> Self {
EncodingOverride
}
pub fn decode<'a>(&self, input: Cow<'a, [u8]>) -> Cow<'a, str> {
decode_utf8_lossy(input)
}
pub fn encode<'a>(&self, input: Cow<'a, str>) -> Cow<'a, [u8]> {
encode_utf8(input)
}
}
pub fn decode_utf8_lossy(input: Cow<[u8]>) -> Cow<str> {
match input {
Cow::Borrowed(bytes) => String::from_utf8_lossy(bytes),
Cow::Owned(bytes) => {
let raw_utf8: *const [u8];
match String::from_utf8_lossy(&bytes) {
Cow::Borrowed(utf8) => raw_utf8 = utf8.as_bytes(),
Cow::Owned(s) => return s.into(),
}
// from_utf8_lossy returned a borrow of `bytes` unchanged.
debug_assert!(raw_utf8 == &*bytes as *const [u8]);
// Reuse the existing `Vec` allocation.
unsafe { String::from_utf8_unchecked(bytes) }.into()
}
}
}
pub fn encode_utf8(input: Cow<str>) -> Cow<[u8]> {
match input {
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
Cow::Owned(s) => Cow::Owned(s.into_bytes())
}
}

View file

@ -0,0 +1,364 @@
// Copyright 2013-2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Parser and serializer for the [`application/x-www-form-urlencoded` syntax](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.
use encoding::EncodingOverride;
use percent_encoding::{percent_encode_byte, percent_decode};
use std::borrow::{Borrow, Cow};
use std::str;
/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// The names and values are percent-decoded. For instance, `%23first=%25try%25` will be
/// converted to `[("#first", "%try%")]`.
#[inline]
pub fn parse(input: &[u8]) -> Parse {
Parse {
input: input,
encoding: EncodingOverride::utf8(),
}
}
/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
///
/// Use `parse(input.as_bytes())` to parse a `&str` string.
///
/// This function is only available if the `query_encoding` Cargo feature is enabled.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
/// after percent-decoding. Defaults to UTF-8.
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
#[cfg(feature = "query_encoding")]
pub fn parse_with_encoding<'a>(input: &'a [u8],
encoding_override: Option<::encoding::EncodingRef>,
use_charset: bool)
-> Result<Parse<'a>, ()> {
use std::ascii::AsciiExt;
let mut encoding = EncodingOverride::from_opt_encoding(encoding_override);
if !(encoding.is_utf8() || input.is_ascii()) {
return Err(())
}
if use_charset {
for sequence in input.split(|&b| b == b'&') {
// No '+' in "_charset_" to replace with ' '.
if sequence.starts_with(b"_charset_=") {
let value = &sequence[b"_charset_=".len()..];
// Skip replacing '+' with ' ' in value since no encoding label contains either:
// https://encoding.spec.whatwg.org/#names-and-labels
if let Some(e) = EncodingOverride::lookup(value) {
encoding = e;
break
}
}
}
}
Ok(Parse {
input: input,
encoding: encoding,
})
}
/// The return type of `parse()`.
#[derive(Copy, Clone)]
pub struct Parse<'a> {
input: &'a [u8],
encoding: EncodingOverride,
}
impl<'a> Iterator for Parse<'a> {
type Item = (Cow<'a, str>, Cow<'a, str>);
fn next(&mut self) -> Option<Self::Item> {
loop {
if self.input.is_empty() {
return None
}
let mut split2 = self.input.splitn(2, |&b| b == b'&');
let sequence = split2.next().unwrap();
self.input = split2.next().unwrap_or(&[][..]);
if sequence.is_empty() {
continue
}
let mut split2 = sequence.splitn(2, |&b| b == b'=');
let name = split2.next().unwrap();
let value = split2.next().unwrap_or(&[][..]);
return Some((
decode(name, self.encoding),
decode(value, self.encoding),
))
}
}
}
fn decode(input: &[u8], encoding: EncodingOverride) -> Cow<str> {
let replaced = replace_plus(input);
encoding.decode(match percent_decode(&replaced).if_any() {
Some(vec) => Cow::Owned(vec),
None => replaced,
})
}
/// Replace b'+' with b' '
fn replace_plus<'a>(input: &'a [u8]) -> Cow<'a, [u8]> {
match input.iter().position(|&b| b == b'+') {
None => Cow::Borrowed(input),
Some(first_position) => {
let mut replaced = input.to_owned();
replaced[first_position] = b' ';
for byte in &mut replaced[first_position + 1..] {
if *byte == b'+' {
*byte = b' ';
}
}
Cow::Owned(replaced)
}
}
}
impl<'a> Parse<'a> {
/// Return a new iterator that yields pairs of `String` instead of pairs of `Cow<str>`.
pub fn into_owned(self) -> ParseIntoOwned<'a> {
ParseIntoOwned { inner: self }
}
}
/// Like `Parse`, but yields pairs of `String` instead of pairs of `Cow<str>`.
pub struct ParseIntoOwned<'a> {
inner: Parse<'a>
}
impl<'a> Iterator for ParseIntoOwned<'a> {
type Item = (String, String);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(k, v)| (k.into_owned(), v.into_owned()))
}
}
/// The [`application/x-www-form-urlencoded` byte serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
///
/// Return an iterator of `&str` slices.
pub fn byte_serialize(input: &[u8]) -> ByteSerialize {
ByteSerialize {
bytes: input,
}
}
/// Return value of `byte_serialize()`.
pub struct ByteSerialize<'a> {
bytes: &'a [u8],
}
fn byte_serialized_unchanged(byte: u8) -> bool {
matches!(byte, b'*' | b'-' | b'.' | b'0' ... b'9' | b'A' ... b'Z' | b'_' | b'a' ... b'z')
}
impl<'a> Iterator for ByteSerialize<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
if let Some((&first, tail)) = self.bytes.split_first() {
if !byte_serialized_unchanged(first) {
self.bytes = tail;
return Some(if first == b' ' { "+" } else { percent_encode_byte(first) })
}
let position = tail.iter().position(|&b| !byte_serialized_unchanged(b));
let (unchanged_slice, remaining) = match position {
// 1 for first_byte + i unchanged in tail
Some(i) => self.bytes.split_at(1 + i),
None => (self.bytes, &[][..]),
};
self.bytes = remaining;
Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.bytes.is_empty() {
(0, Some(0))
} else {
(1, Some(self.bytes.len()))
}
}
}
/// The [`application/x-www-form-urlencoded` serializer](
/// https://url.spec.whatwg.org/#concept-urlencoded-serializer).
pub struct Serializer<T: Target> {
target: Option<T>,
start_position: usize,
encoding: EncodingOverride,
}
pub trait Target {
fn as_mut_string(&mut self) -> &mut String;
fn finish(self) -> Self::Finished;
type Finished;
}
impl Target for String {
fn as_mut_string(&mut self) -> &mut String { self }
fn finish(self) -> Self { self }
type Finished = Self;
}
impl<'a> Target for &'a mut String {
fn as_mut_string(&mut self) -> &mut String { &mut **self }
fn finish(self) -> Self { self }
type Finished = Self;
}
// `as_mut_string` string here exposes the internal serialization of an `Url`,
// which should not be exposed to users.
// We achieve that by not giving users direct access to `UrlQuery`:
// * Its fields are private
// (and so can not be constructed with struct literal syntax outside of this crate),
// * It has no constructor
// * It is only visible (on the type level) to users in the return type of
// `Url::query_pairs_mut` which is `Serializer<UrlQuery>`
// * `Serializer` keeps its target in a private field
// * Unlike in other `Target` impls, `UrlQuery::finished` does not return `Self`.
impl<'a> Target for ::UrlQuery<'a> {
fn as_mut_string(&mut self) -> &mut String { &mut self.url.serialization }
fn finish(self) -> &'a mut ::Url { self.url }
type Finished = &'a mut ::Url;
}
impl<T: Target> Serializer<T> {
/// Create a new `application/x-www-form-urlencoded` serializer for the given target.
///
/// If the target is non-empty,
/// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
pub fn new(target: T) -> Self {
Self::for_suffix(target, 0)
}
/// Create a new `application/x-www-form-urlencoded` serializer
/// for a suffix of the given target.
///
/// If that suffix is non-empty,
/// its content is assumed to already be in `application/x-www-form-urlencoded` syntax.
pub fn for_suffix(mut target: T, start_position: usize) -> Self {
&target.as_mut_string()[start_position..]; // Panic if out of bounds
Serializer {
target: Some(target),
start_position: start_position,
encoding: EncodingOverride::utf8(),
}
}
/// Remove any existing name/value pair.
///
/// Panics if called after `.finish()`.
pub fn clear(&mut self) -> &mut Self {
string(&mut self.target).truncate(self.start_position);
self
}
/// Set the character encoding to be used for names and values before percent-encoding.
#[cfg(feature = "query_encoding")]
pub fn encoding_override(&mut self, new: Option<::encoding::EncodingRef>) -> &mut Self {
self.encoding = EncodingOverride::from_opt_encoding(new).to_output_encoding();
self
}
/// Serialize and append a name/value pair.
///
/// Panics if called after `.finish()`.
pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
append_pair(string(&mut self.target), self.start_position, self.encoding, name, value);
self
}
/// Serialize and append a number of name/value pairs.
///
/// This simply calls `append_pair` repeatedly.
/// This can be more convenient, so the user doesn’t need to introduce a block
/// to limit the scope of `Serializer`’s borrow of its string.
///
/// Panics if called after `.finish()`.
pub fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self
where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> {
{
let string = string(&mut self.target);
for pair in iter {
let &(ref k, ref v) = pair.borrow();
append_pair(string, self.start_position, self.encoding, k.as_ref(), v.as_ref());
}
}
self
}
/// Add a name/value pair whose name is `_charset_`
/// and whose value is the character encoding’s name.
/// (See the `encoding_override()` method.)
///
/// Panics if called after `.finish()`.
#[cfg(feature = "query_encoding")]
pub fn append_charset(&mut self) -> &mut Self {
{
let string = string(&mut self.target);
append_separator_if_needed(string, self.start_position);
string.push_str("_charset_=");
string.push_str(self.encoding.name());
}
self
}
/// If this serializer was constructed with a string, take and return that string.
///
/// ```rust
/// use url::form_urlencoded;
/// let encoded: String = form_urlencoded::Serializer::new(String::new())
/// .append_pair("foo", "bar & baz")
/// .append_pair("saison", "Été+hiver")
/// .finish();
/// assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver");
/// ```
///
/// Panics if called more than once.
pub fn finish(&mut self) -> T::Finished {
self.target.take().expect("url::form_urlencoded::Serializer double finish").finish()
}
}
fn append_separator_if_needed(string: &mut String, start_position: usize) {
if string.len() > start_position {
string.push('&')
}
}
fn string<T: Target>(target: &mut Option<T>) -> &mut String {
target.as_mut().expect("url::form_urlencoded::Serializer finished").as_mut_string()
}
fn append_pair(string: &mut String, start_position: usize, encoding: EncodingOverride,
name: &str, value: &str) {
append_separator_if_needed(string, start_position);
string.extend(byte_serialize(&encoding.encode(name.into())));
string.push('=');
string.extend(byte_serialize(&encoding.encode(value.into())));
}

418
third_party/rust/url/src/host.rs vendored Normal file
View file

@ -0,0 +1,418 @@
// Copyright 2013-2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[cfg(feature = "heapsize")] use heapsize::HeapSizeOf;
use std::cmp;
use std::fmt::{self, Formatter};
use std::io;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
use std::vec;
use parser::{ParseResult, ParseError};
use percent_encoding::percent_decode;
use idna;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum HostInternal {
None,
Domain,
Ipv4(Ipv4Addr),
Ipv6(Ipv6Addr),
}
#[cfg(feature = "heapsize")]
known_heap_size!(0, HostInternal);
impl<S> From<Host<S>> for HostInternal {
fn from(host: Host<S>) -> HostInternal {
match host {
Host::Domain(_) => HostInternal::Domain,
Host::Ipv4(address) => HostInternal::Ipv4(address),
Host::Ipv6(address) => HostInternal::Ipv6(address),
}
}
}
/// The host name of an URL.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Host<S=String> {
/// A DNS domain name, as '.' dot-separated labels.
/// Non-ASCII labels are encoded in punycode per IDNA.
Domain(S),
/// An IPv4 address.
/// `Url::host_str` returns the serialization of this address,
/// as four decimal integers separated by `.` dots.
Ipv4(Ipv4Addr),
/// An IPv6 address.
/// `Url::host_str` returns the serialization of that address between `[` and `]` brackets,
/// in the format per [RFC 5952 *A Recommendation
/// for IPv6 Address Text Representation*](https://tools.ietf.org/html/rfc5952):
/// lowercase hexadecimal with maximal `::` compression.
Ipv6(Ipv6Addr),
}
#[cfg(feature = "heapsize")]
impl<S: HeapSizeOf> HeapSizeOf for Host<S> {
fn heap_size_of_children(&self) -> usize {
match *self {
Host::Domain(ref s) => s.heap_size_of_children(),
_ => 0,
}
}
}
impl<'a> Host<&'a str> {
/// Return a copy of `self` that owns an allocated `String` but does not borrow an `&Url`.
pub fn to_owned(&self) -> Host<String> {
match *self {
Host::Domain(domain) => Host::Domain(domain.to_owned()),
Host::Ipv4(address) => Host::Ipv4(address),
Host::Ipv6(address) => Host::Ipv6(address),
}
}
}
impl Host<String> {
/// Parse a host: either an IPv6 address in [] square brackets, or a domain.
///
/// https://url.spec.whatwg.org/#host-parsing
pub fn parse(input: &str) -> Result<Self, ParseError> {
if input.starts_with("[") {
if !input.ends_with("]") {
return Err(ParseError::InvalidIpv6Address)
}
return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6)
}
let domain = percent_decode(input.as_bytes()).decode_utf8_lossy();
let domain = try!(idna::domain_to_ascii(&domain));
if domain.find(|c| matches!(c,
'\0' | '\t' | '\n' | '\r' | ' ' | '#' | '%' | '/' | ':' | '?' | '@' | '[' | '\\' | ']'
)).is_some() {
return Err(ParseError::InvalidDomainCharacter)
}
if let Some(address) = try!(parse_ipv4addr(&domain)) {
Ok(Host::Ipv4(address))
} else {
Ok(Host::Domain(domain.into()))
}
}
}
impl<S: AsRef<str>> fmt::Display for Host<S> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Host::Domain(ref domain) => domain.as_ref().fmt(f),
Host::Ipv4(ref addr) => addr.fmt(f),
Host::Ipv6(ref addr) => {
try!(f.write_str("["));
try!(write_ipv6(addr, f));
f.write_str("]")
}
}
}
}
/// This mostly exists because coherence rules don’t allow us to implement
/// `ToSocketAddrs for (Host<S>, u16)`.
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> {
HostAndPort {
host: self.host.to_owned(),
port: self.port
}
}
}
impl<S: AsRef<str>> ToSocketAddrs for HostAndPort<S> {
type Iter = SocketAddrs;
fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
let port = self.port;
match self.host {
Host::Domain(ref domain) => Ok(SocketAddrs {
// FIXME: use std::net::lookup_host when it’s stable.
state: SocketAddrsState::Domain(try!((domain.as_ref(), port).to_socket_addrs()))
}),
Host::Ipv4(address) => Ok(SocketAddrs {
state: SocketAddrsState::One(SocketAddr::V4(SocketAddrV4::new(address, port)))
}),
Host::Ipv6(address) => Ok(SocketAddrs {
state: SocketAddrsState::One(SocketAddr::V6(SocketAddrV6::new(address, port, 0, 0)))
}),
}
}
}
/// Socket addresses for an URL.
pub struct SocketAddrs {
state: SocketAddrsState
}
enum SocketAddrsState {
Domain(vec::IntoIter<SocketAddr>),
One(SocketAddr),
Done,
}
impl Iterator for SocketAddrs {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
match self.state {
SocketAddrsState::Domain(ref mut iter) => iter.next(),
SocketAddrsState::One(s) => {
self.state = SocketAddrsState::Done;
Some(s)
}
SocketAddrsState::Done => None
}
}
}
fn write_ipv6(addr: &Ipv6Addr, f: &mut Formatter) -> fmt::Result {
let segments = addr.segments();
let (compress_start, compress_end) = longest_zero_sequence(&segments);
let mut i = 0;
while i < 8 {
if i == compress_start {
try!(f.write_str(":"));
if i == 0 {
try!(f.write_str(":"));
}
if compress_end < 8 {
i = compress_end;
} else {
break;
}
}
try!(write!(f, "{:x}", segments[i as usize]));
if i < 7 {
try!(f.write_str(":"));
}
i += 1;
}
Ok(())
}
fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) {
let mut longest = -1;
let mut longest_length = -1;
let mut start = -1;
macro_rules! finish_sequence(
($end: expr) => {
if start >= 0 {
let length = $end - start;
if length > longest_length {
longest = start;
longest_length = length;
}
}
};
);
for i in 0..8 {
if pieces[i as usize] == 0 {
if start < 0 {
start = i;
}
} else {
finish_sequence!(i);
start = -1;
}
}
finish_sequence!(8);
(longest, longest + longest_length)
}
fn parse_ipv4number(mut input: &str) -> Result<u32, ()> {
let mut r = 10;
if input.starts_with("0x") || input.starts_with("0X") {
input = &input[2..];
r = 16;
} else if input.len() >= 2 && input.starts_with("0") {
input = &input[1..];
r = 8;
}
if input.is_empty() {
return Ok(0);
}
if input.starts_with("+") {
return Err(())
}
match u32::from_str_radix(&input, r) {
Ok(number) => Ok(number),
Err(_) => Err(()),
}
}
fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
if input.is_empty() {
return Ok(None)
}
let mut parts: Vec<&str> = input.split('.').collect();
if parts.last() == Some(&"") {
parts.pop();
}
if parts.len() > 4 {
return Ok(None);
}
let mut numbers: Vec<u32> = Vec::new();
for part in parts {
if part == "" {
return Ok(None);
}
if let Ok(n) = parse_ipv4number(part) {
numbers.push(n);
} else {
return Ok(None);
}
}
let mut ipv4 = numbers.pop().expect("a non-empty list of numbers");
// Equivalent to: ipv4 >= 256 ** (4 − numbers.len())
if ipv4 > u32::max_value() >> (8 * numbers.len() as u32) {
return Err(ParseError::InvalidIpv4Address);
}
if numbers.iter().any(|x| *x > 255) {
return Err(ParseError::InvalidIpv4Address);
}
for (counter, n) in numbers.iter().enumerate() {
ipv4 += n << (8 * (3 - counter as u32))
}
Ok(Some(Ipv4Addr::from(ipv4)))
}
fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> {
let input = input.as_bytes();
let len = input.len();
let mut is_ip_v4 = false;
let mut pieces = [0, 0, 0, 0, 0, 0, 0, 0];
let mut piece_pointer = 0;
let mut compress_pointer = None;
let mut i = 0;
if len < 2 {
return Err(ParseError::InvalidIpv6Address)
}
if input[0] == b':' {
if input[1] != b':' {
return Err(ParseError::InvalidIpv6Address)
}
i = 2;
piece_pointer = 1;
compress_pointer = Some(1);
}
while i < len {
if piece_pointer == 8 {
return Err(ParseError::InvalidIpv6Address)
}
if input[i] == b':' {
if compress_pointer.is_some() {
return Err(ParseError::InvalidIpv6Address)
}
i += 1;
piece_pointer += 1;
compress_pointer = Some(piece_pointer);
continue
}
let start = i;
let end = cmp::min(len, start + 4);
let mut value = 0u16;
while i < end {
match (input[i] as char).to_digit(16) {
Some(digit) => {
value = value * 0x10 + digit as u16;
i += 1;
},
None => break
}
}
if i < len {
match input[i] {
b'.' => {
if i == start {
return Err(ParseError::InvalidIpv6Address)
}
i = start;
is_ip_v4 = true;
},
b':' => {
i += 1;
if i == len {
return Err(ParseError::InvalidIpv6Address)
}
},
_ => return Err(ParseError::InvalidIpv6Address)
}
}
if is_ip_v4 {
break
}
pieces[piece_pointer] = value;
piece_pointer += 1;
}
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;
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)
}
}
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 {
piece_pointer += 1;
}
i += 1;
if dots_seen == 3 && i < len {
return Err(ParseError::InvalidIpv6Address)
}
dots_seen += 1;
}
}
match compress_pointer {
Some(compress_pointer) => {
let mut swaps = piece_pointer - compress_pointer;
piece_pointer = 7;
while swaps > 0 {
pieces[piece_pointer] = pieces[compress_pointer + swaps - 1];
pieces[compress_pointer + swaps - 1] = 0;
swaps -= 1;
piece_pointer -= 1;
}
}
_ => if piece_pointer != 8 {
return Err(ParseError::InvalidIpv6Address)
}
}
Ok(Ipv6Addr::new(pieces[0], pieces[1], pieces[2], pieces[3],
pieces[4], pieces[5], pieces[6], pieces[7]))
}

1456
third_party/rust/url/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load diff

114
third_party/rust/url/src/origin.rs vendored Normal file
View file

@ -0,0 +1,114 @@
// Copyright 2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[cfg(feature = "heapsize")] use heapsize::HeapSizeOf;
use host::Host;
use idna::domain_to_unicode;
use parser::default_port;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use Url;
pub fn url_origin(url: &Url) -> Origin {
let scheme = url.scheme();
match scheme {
"blob" => {
let result = Url::parse(url.path());
match result {
Ok(ref url) => url_origin(url),
Err(_) => Origin::new_opaque()
}
},
"ftp" | "gopher" | "http" | "https" | "ws" | "wss" => {
Origin::Tuple(scheme.to_owned(), url.host().unwrap().to_owned(),
url.port_or_known_default().unwrap())
},
// TODO: Figure out what to do if the scheme is a file
"file" => Origin::new_opaque(),
_ => Origin::new_opaque()
}
}
/// The origin of an URL
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Origin {
/// A globally unique identifier
Opaque(OpaqueOrigin),
/// Consists of the URL's scheme, host and port
Tuple(String, Host<String>, u16)
}
#[cfg(feature = "heapsize")]
impl HeapSizeOf for Origin {
fn heap_size_of_children(&self) -> usize {
match *self {
Origin::Tuple(ref scheme, ref host, _) => {
scheme.heap_size_of_children() +
host.heap_size_of_children()
},
_ => 0,
}
}
}
impl Origin {
/// Creates a new opaque origin that is only equal to itself.
pub fn new_opaque() -> Origin {
static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
Origin::Opaque(OpaqueOrigin(COUNTER.fetch_add(1, Ordering::SeqCst)))
}
/// Return whether this origin is a (scheme, host, port) tuple
/// (as opposed to an opaque origin).
pub fn is_tuple(&self) -> bool {
matches!(*self, Origin::Tuple(..))
}
/// https://html.spec.whatwg.org/multipage/#ascii-serialisation-of-an-origin
pub fn ascii_serialization(&self) -> String {
match *self {
Origin::Opaque(_) => "null".to_owned(),
Origin::Tuple(ref scheme, ref host, port) => {
if default_port(scheme) == Some(port) {
format!("{}://{}", scheme, host)
} else {
format!("{}://{}:{}", scheme, host, port)
}
}
}
}
/// https://html.spec.whatwg.org/multipage/#unicode-serialisation-of-an-origin
pub fn unicode_serialization(&self) -> String {
match *self {
Origin::Opaque(_) => "null".to_owned(),
Origin::Tuple(ref scheme, ref host, port) => {
let host = match *host {
Host::Domain(ref domain) => {
let (domain, _errors) = domain_to_unicode(domain);
Host::Domain(domain)
}
_ => host.clone()
};
if default_port(scheme) == Some(port) {
format!("{}://{}", scheme, host)
} else {
format!("{}://{}:{}", scheme, host, port)
}
}
}
}
}
/// Opaque identifier for URLs that have file or other schemes
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct OpaqueOrigin(usize);
#[cfg(feature = "heapsize")]
known_heap_size!(0, OpaqueOrigin);

1179
third_party/rust/url/src/parser.rs vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,187 @@
// Copyright 2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use parser::{self, SchemeType, to_u32};
use std::str;
use Url;
/// Exposes methods to manipulate the path of an URL that is not cannot-be-base.
///
/// The path always starts with a `/` slash, and is made of slash-separated segments.
/// There is always at least one segment (which may be the empty string).
///
/// Examples:
///
/// ```rust
/// # use url::Url;
/// let mut url = Url::parse("mailto:me@example.com").unwrap();
/// assert!(url.path_segments_mut().is_err());
///
/// let mut url = Url::parse("http://example.net/foo/index.html").unwrap();
/// url.path_segments_mut().unwrap().pop().push("img").push("2/100%.png");
/// assert_eq!(url.as_str(), "http://example.net/foo/img/2%2F100%25.png");
/// ```
pub struct PathSegmentsMut<'a> {
url: &'a mut Url,
after_first_slash: usize,
after_path: String,
old_after_path_position: u32,
}
// Not re-exported outside the crate
pub fn new(url: &mut Url) -> PathSegmentsMut {
let after_path = url.take_after_path();
let old_after_path_position = to_u32(url.serialization.len()).unwrap();
debug_assert!(url.byte_at(url.path_start) == b'/');
PathSegmentsMut {
after_first_slash: url.path_start as usize + "/".len(),
url: url,
old_after_path_position: old_after_path_position,
after_path: after_path,
}
}
impl<'a> Drop for PathSegmentsMut<'a> {
fn drop(&mut self) {
self.url.restore_after_path(self.old_after_path_position, &self.after_path)
}
}
impl<'a> PathSegmentsMut<'a> {
/// Remove all segments in the path, leaving the minimal `url.path() == "/"`.
///
/// Returns `&mut Self` so that method calls can be chained.
///
/// Example:
///
/// ```rust
/// # use url::Url;
/// let mut url = Url::parse("https://github.com/servo/rust-url/").unwrap();
/// url.path_segments_mut().unwrap().clear().push("logout");
/// assert_eq!(url.as_str(), "https://github.com/logout");
/// ```
pub fn clear(&mut self) -> &mut Self {
self.url.serialization.truncate(self.after_first_slash);
self
}
/// Remove the last segment of this URL’s path if it is empty,
/// except if these was only one segment to begin with.
///
/// In other words, remove one path trailing slash, if any,
/// unless it is also the initial slash (so this does nothing if `url.path() == "/")`.
///
/// Returns `&mut Self` so that method calls can be chained.
///
/// Example:
///
/// ```rust
/// # use url::Url;
/// let mut url = Url::parse("https://github.com/servo/rust-url/").unwrap();
/// url.path_segments_mut().unwrap().push("pulls");
/// assert_eq!(url.as_str(), "https://github.com/servo/rust-url//pulls");
///
/// let mut url = Url::parse("https://github.com/servo/rust-url/").unwrap();
/// url.path_segments_mut().unwrap().pop_if_empty().push("pulls");
/// assert_eq!(url.as_str(), "https://github.com/servo/rust-url/pulls");
/// ```
pub fn pop_if_empty(&mut self) -> &mut Self {
if self.url.serialization[self.after_first_slash..].ends_with('/') {
self.url.serialization.pop();
}
self
}
/// Remove the last segment of this URL’s path.
///
/// If the path only has one segment, make it empty such that `url.path() == "/"`.
///
/// Returns `&mut Self` so that method calls can be chained.
pub fn pop(&mut self) -> &mut Self {
let last_slash = self.url.serialization[self.after_first_slash..].rfind('/').unwrap_or(0);
self.url.serialization.truncate(self.after_first_slash + last_slash);
self
}
/// Append the given segment at the end of this URL’s path.
///
/// See the documentation for `.extend()`.
///
/// Returns `&mut Self` so that method calls can be chained.
pub fn push(&mut self, segment: &str) -> &mut Self {
self.extend(Some(segment))
}
/// Append each segment from the given iterator at the end of this URL’s path.
///
/// Each segment is percent-encoded like in `Url::parse` or `Url::join`,
/// except that `%` and `/` characters are also encoded (to `%25` and `%2F`).
/// This is unlike `Url::parse` where `%` is left as-is in case some of the input
/// is already percent-encoded, and `/` denotes a path segment separator.)
///
/// Note that, in addition to slashes between new segments,
/// this always adds a slash between the existing path and the new segments
/// *except* if the existing path is `"/"`.
/// If the previous last segment was empty (if the path had a trailing slash)
/// the path after `.extend()` will contain two consecutive slashes.
/// If that is undesired, call `.pop_if_empty()` first.
///
/// To obtain a behavior similar to `Url::join`, call `.pop()` unconditionally first.
///
/// Returns `&mut Self` so that method calls can be chained.
///
/// Example:
///
/// ```rust
/// # use url::Url;
/// let mut url = Url::parse("https://github.com/").unwrap();
/// let org = "servo";
/// let repo = "rust-url";
/// let issue_number = "188";
/// url.path_segments_mut().unwrap().extend(&[org, repo, "issues", issue_number]);
/// assert_eq!(url.as_str(), "https://github.com/servo/rust-url/issues/188");
/// ```
///
/// In order to make sure that parsing the serialization of an URL gives the same URL,
/// a segment is ignored if it is `"."` or `".."`:
///
/// ```rust
/// # use url::Url;
/// let mut url = Url::parse("https://github.com/servo").unwrap();
/// url.path_segments_mut().unwrap().extend(&["..", "rust-url", ".", "pulls"]);
/// assert_eq!(url.as_str(), "https://github.com/servo/rust-url/pulls");
/// ```
pub fn extend<I>(&mut self, segments: I) -> &mut Self
where I: IntoIterator, I::Item: AsRef<str> {
let scheme_type = SchemeType::from(self.url.scheme());
let path_start = self.url.path_start as usize;
self.url.mutate(|parser| {
parser.context = parser::Context::PathSegmentSetter;
for segment in segments {
let segment = segment.as_ref();
if matches!(segment, "." | "..") {
continue
}
if parser.serialization.len() > path_start + 1 {
parser.serialization.push('/');
}
let mut has_host = true; // FIXME account for this?
parser.parse_path(scheme_type, &mut has_host, path_start,
parser::Input::new(segment));
}
});
self
}
/// For internal testing, not part of the public API.
#[doc(hidden)]
pub fn assert_url_invariants(&mut self) -> &mut Self {
self.url.assert_invariants();
self
}
}

View file

@ -0,0 +1,344 @@
// Copyright 2013-2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use encoding;
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::fmt;
use std::slice;
use std::str;
/// Represents a set of characters / bytes that should be percent-encoded.
///
/// See [encode sets specification](http://url.spec.whatwg.org/#simple-encode-set).
///
/// Different characters need to be encoded in different parts of an URL.
/// For example, a literal `?` question mark in an URL’s path would indicate
/// the start of the query string.
/// A question mark meant to be part of the path therefore needs to be percent-encoded.
/// In the query string however, a question mark does not have any special meaning
/// and does not need to be percent-encoded.
///
/// A few sets are defined in this module.
/// Use the [`define_encode_set!`](../macro.define_encode_set!.html) macro to define different ones.
pub trait EncodeSet: Clone {
/// Called with UTF-8 bytes rather than code points.
/// Should return true for all non-ASCII bytes.
fn contains(&self, byte: u8) -> bool;
}
/// Define a new struct
/// that implements the [`EncodeSet`](percent_encoding/trait.EncodeSet.html) trait,
/// for use in [`percent_decode()`](percent_encoding/fn.percent_encode.html)
/// and related functions.
///
/// Parameters are characters to include in the set in addition to those of the base set.
/// See [encode sets specification](http://url.spec.whatwg.org/#simple-encode-set).
///
/// Example
/// =======
///
/// ```rust
/// #[macro_use] extern crate url;
/// use url::percent_encoding::{utf8_percent_encode, SIMPLE_ENCODE_SET};
/// define_encode_set! {
/// /// This encode set is used in the URL parser for query strings.
/// pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'}
/// }
/// # fn main() {
/// assert_eq!(utf8_percent_encode("foo bar", QUERY_ENCODE_SET).collect::<String>(), "foo%20bar");
/// # }
/// ```
#[macro_export]
macro_rules! define_encode_set {
($(#[$attr: meta])* pub $name: ident = [$base_set: expr] | {$($ch: pat),*}) => {
$(#[$attr])*
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct $name;
impl $crate::percent_encoding::EncodeSet for $name {
#[inline]
fn contains(&self, byte: u8) -> bool {
match byte as char {
$(
$ch => true,
)*
_ => $base_set.contains(byte)
}
}
}
}
}
/// This encode set is used for the path of cannot-be-a-base URLs.
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct SIMPLE_ENCODE_SET;
impl EncodeSet for SIMPLE_ENCODE_SET {
#[inline]
fn contains(&self, byte: u8) -> bool {
byte < 0x20 || byte > 0x7E
}
}
define_encode_set! {
/// This encode set is used in the URL parser for query strings.
pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'}
}
define_encode_set! {
/// This encode set is used for path components.
pub DEFAULT_ENCODE_SET = [QUERY_ENCODE_SET] | {'`', '?', '{', '}'}
}
define_encode_set! {
/// This encode set is used for on '/'-separated path segment
pub PATH_SEGMENT_ENCODE_SET = [DEFAULT_ENCODE_SET] | {'%', '/'}
}
define_encode_set! {
/// This encode set is used for username and password.
pub USERINFO_ENCODE_SET = [DEFAULT_ENCODE_SET] | {
'/', ':', ';', '=', '@', '[', '\\', ']', '^', '|'
}
}
/// Return the percent-encoding of the given bytes.
///
/// This is unconditional, unlike `percent_encode()` which uses an encode set.
pub fn percent_encode_byte(byte: u8) -> &'static str {
let index = usize::from(byte) * 3;
&"\
%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F\
%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F\
%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F\
%30%31%32%33%34%35%36%37%38%39%3A%3B%3C%3D%3E%3F\
%40%41%42%43%44%45%46%47%48%49%4A%4B%4C%4D%4E%4F\
%50%51%52%53%54%55%56%57%58%59%5A%5B%5C%5D%5E%5F\
%60%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F\
%70%71%72%73%74%75%76%77%78%79%7A%7B%7C%7D%7E%7F\
%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F\
%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F\
%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF\
%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF\
%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF\
%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF\
%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF\
%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF\
"[index..index + 3]
}
/// Percent-encode the given bytes with the given encode set.
///
/// The encode set define which bytes (in addition to non-ASCII and controls)
/// need to be percent-encoded.
/// The choice of this set depends on context.
/// For example, `?` needs to be encoded in an URL path but not in a query string.
///
/// The return value is an iterator of `&str` slices (so it has a `.collect::<String>()` method)
/// that also implements `Display` and `Into<Cow<str>>`.
/// The latter returns `Cow::Borrowed` when none of the bytes in `input`
/// are in the given encode set.
#[inline]
pub fn percent_encode<E: EncodeSet>(input: &[u8], encode_set: E) -> PercentEncode<E> {
PercentEncode {
bytes: input,
encode_set: encode_set,
}
}
/// Percent-encode the UTF-8 encoding of the given string.
///
/// See `percent_encode()` for how to use the return value.
#[inline]
pub fn utf8_percent_encode<E: EncodeSet>(input: &str, encode_set: E) -> PercentEncode<E> {
percent_encode(input.as_bytes(), encode_set)
}
/// The return type of `percent_encode()` and `utf8_percent_encode()`.
#[derive(Clone)]
pub struct PercentEncode<'a, E: EncodeSet> {
bytes: &'a [u8],
encode_set: E,
}
impl<'a, E: EncodeSet> Iterator for PercentEncode<'a, E> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
if let Some((&first_byte, remaining)) = self.bytes.split_first() {
if self.encode_set.contains(first_byte) {
self.bytes = remaining;
Some(percent_encode_byte(first_byte))
} else {
assert!(first_byte.is_ascii());
for (i, &byte) in remaining.iter().enumerate() {
if self.encode_set.contains(byte) {
// 1 for first_byte + i for previous iterations of this loop
let (unchanged_slice, remaining) = self.bytes.split_at(1 + i);
self.bytes = remaining;
return Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
} else {
assert!(byte.is_ascii());
}
}
let unchanged_slice = self.bytes;
self.bytes = &[][..];
Some(unsafe { str::from_utf8_unchecked(unchanged_slice) })
}
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.bytes.is_empty() {
(0, Some(0))
} else {
(1, Some(self.bytes.len()))
}
}
}
impl<'a, E: EncodeSet> fmt::Display for PercentEncode<'a, E> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
for c in (*self).clone() {
try!(formatter.write_str(c))
}
Ok(())
}
}
impl<'a, E: EncodeSet> From<PercentEncode<'a, E>> for Cow<'a, str> {
fn from(mut iter: PercentEncode<'a, E>) -> Self {
match iter.next() {
None => "".into(),
Some(first) => {
match iter.next() {
None => first.into(),
Some(second) => {
let mut string = first.to_owned();
string.push_str(second);
string.extend(iter);
string.into()
}
}
}
}
}
}
/// Percent-decode the given bytes.
///
/// The return value is an iterator of decoded `u8` bytes
/// that also implements `Into<Cow<u8>>`
/// (which returns `Cow::Borrowed` when `input` contains no percent-encoded sequence)
/// and has `decode_utf8()` and `decode_utf8_lossy()` methods.
#[inline]
pub fn percent_decode<'a>(input: &'a [u8]) -> PercentDecode<'a> {
PercentDecode {
bytes: input.iter()
}
}
/// The return type of `percent_decode()`.
#[derive(Clone)]
pub struct PercentDecode<'a> {
bytes: slice::Iter<'a, u8>,
}
fn after_percent_sign(iter: &mut slice::Iter<u8>) -> Option<u8> {
let initial_iter = iter.clone();
let h = iter.next().and_then(|&b| (b as char).to_digit(16));
let l = iter.next().and_then(|&b| (b as char).to_digit(16));
if let (Some(h), Some(l)) = (h, l) {
Some(h as u8 * 0x10 + l as u8)
} else {
*iter = initial_iter;
None
}
}
impl<'a> Iterator for PercentDecode<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.bytes.next().map(|&byte| {
if byte == b'%' {
after_percent_sign(&mut self.bytes).unwrap_or(byte)
} else {
byte
}
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let bytes = self.bytes.len();
(bytes / 3, Some(bytes))
}
}
impl<'a> From<PercentDecode<'a>> for Cow<'a, [u8]> {
fn from(iter: PercentDecode<'a>) -> Self {
match iter.if_any() {
Some(vec) => Cow::Owned(vec),
None => Cow::Borrowed(iter.bytes.as_slice()),
}
}
}
impl<'a> PercentDecode<'a> {
/// If the percent-decoding is different from the input, return it as a new bytes vector.
pub fn if_any(&self) -> Option<Vec<u8>> {
let mut bytes_iter = self.bytes.clone();
while bytes_iter.find(|&&b| b == b'%').is_some() {
if let Some(decoded_byte) = after_percent_sign(&mut bytes_iter) {
let initial_bytes = self.bytes.as_slice();
let unchanged_bytes_len = initial_bytes.len() - bytes_iter.len() - 3;
let mut decoded = initial_bytes[..unchanged_bytes_len].to_owned();
decoded.push(decoded_byte);
decoded.extend(PercentDecode {
bytes: bytes_iter
});
return Some(decoded)
}
}
// Nothing to decode
None
}
/// Decode the result of percent-decoding as UTF-8.
///
/// This is return `Err` when the percent-decoded bytes are not well-formed in UTF-8.
pub fn decode_utf8(self) -> Result<Cow<'a, str>, str::Utf8Error> {
match self.clone().into() {
Cow::Borrowed(bytes) => {
match str::from_utf8(bytes) {
Ok(s) => Ok(s.into()),
Err(e) => Err(e),
}
}
Cow::Owned(bytes) => {
match String::from_utf8(bytes) {
Ok(s) => Ok(s.into()),
Err(e) => Err(e.utf8_error()),
}
}
}
}
/// Decode the result of percent-decoding as UTF-8, lossily.
///
/// Invalid UTF-8 percent-encoded byte sequences will be replaced <20> U+FFFD,
/// the replacement character.
pub fn decode_utf8_lossy(self) -> Cow<'a, str> {
encoding::decode_utf8_lossy(self.clone().into())
}
}

217
third_party/rust/url/src/quirks.rs vendored Normal file
View file

@ -0,0 +1,217 @@
// Copyright 2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Getters and setters for URL components implemented per https://url.spec.whatwg.org/#api
//!
//! Unless you need to be interoperable with web browsers,
//! you probably want to use `Url` method instead.
use {Url, Position, Host, ParseError, idna};
use parser::{Parser, SchemeType, default_port, Context, Input};
/// https://url.spec.whatwg.org/#dom-url-domaintoascii
pub fn domain_to_ascii(domain: &str) -> String {
match Host::parse(domain) {
Ok(Host::Domain(domain)) => domain,
_ => String::new(),
}
}
/// https://url.spec.whatwg.org/#dom-url-domaintounicode
pub fn domain_to_unicode(domain: &str) -> String {
match Host::parse(domain) {
Ok(Host::Domain(ref domain)) => {
let (unicode, _errors) = idna::domain_to_unicode(domain);
unicode
}
_ => String::new(),
}
}
/// Getter for https://url.spec.whatwg.org/#dom-url-href
pub fn href(url: &Url) -> &str {
url.as_str()
}
/// Setter for https://url.spec.whatwg.org/#dom-url-href
pub fn set_href(url: &mut Url, value: &str) -> Result<(), ParseError> {
*url = try!(Url::parse(value));
Ok(())
}
/// Getter for https://url.spec.whatwg.org/#dom-url-origin
pub fn origin(url: &Url) -> String {
url.origin().unicode_serialization()
}
/// Getter for https://url.spec.whatwg.org/#dom-url-protocol
#[inline]
pub fn protocol(url: &Url) -> &str {
&url.as_str()[..url.scheme().len() + ":".len()]
}
/// Setter for https://url.spec.whatwg.org/#dom-url-protocol
pub fn set_protocol(url: &mut Url, mut new_protocol: &str) -> Result<(), ()> {
// The scheme state in the spec ignores everything after the first `:`,
// but `set_scheme` errors if there is more.
if let Some(position) = new_protocol.find(':') {
new_protocol = &new_protocol[..position];
}
url.set_scheme(new_protocol)
}
/// Getter for https://url.spec.whatwg.org/#dom-url-username
#[inline]
pub fn username(url: &Url) -> &str {
url.username()
}
/// Setter for https://url.spec.whatwg.org/#dom-url-username
pub fn set_username(url: &mut Url, new_username: &str) -> Result<(), ()> {
url.set_username(new_username)
}
/// Getter for https://url.spec.whatwg.org/#dom-url-password
#[inline]
pub fn password(url: &Url) -> &str {
url.password().unwrap_or("")
}
/// Setter for https://url.spec.whatwg.org/#dom-url-password
pub fn set_password(url: &mut Url, new_password: &str) -> Result<(), ()> {
url.set_password(if new_password.is_empty() { None } else { Some(new_password) })
}
/// Getter for https://url.spec.whatwg.org/#dom-url-host
#[inline]
pub fn host(url: &Url) -> &str {
&url[Position::BeforeHost..Position::AfterPort]
}
/// Setter for https://url.spec.whatwg.org/#dom-url-host
pub fn set_host(url: &mut Url, new_host: &str) -> Result<(), ()> {
if url.cannot_be_a_base() {
return Err(())
}
let host;
let opt_port;
{
let scheme = url.scheme();
let result = Parser::parse_host(Input::new(new_host), SchemeType::from(scheme));
match result {
Ok((h, remaining)) => {
host = h;
opt_port = if let Some(remaining) = remaining.split_prefix(':') {
Parser::parse_port(remaining, || default_port(scheme), Context::Setter)
.ok().map(|(port, _remaining)| port)
} else {
None
};
}
Err(_) => return Err(())
}
}
url.set_host_internal(host, opt_port);
Ok(())
}
/// Getter for https://url.spec.whatwg.org/#dom-url-hostname
#[inline]
pub fn hostname(url: &Url) -> &str {
url.host_str().unwrap_or("")
}
/// Setter for https://url.spec.whatwg.org/#dom-url-hostname
pub fn set_hostname(url: &mut Url, new_hostname: &str) -> Result<(), ()> {
if url.cannot_be_a_base() {
return Err(())
}
let result = Parser::parse_host(Input::new(new_hostname), SchemeType::from(url.scheme()));
if let Ok((host, _remaining)) = result {
url.set_host_internal(host, None);
Ok(())
} else {
Err(())
}
}
/// Getter for https://url.spec.whatwg.org/#dom-url-port
#[inline]
pub fn port(url: &Url) -> &str {
&url[Position::BeforePort..Position::AfterPort]
}
/// Setter for https://url.spec.whatwg.org/#dom-url-port
pub fn set_port(url: &mut Url, new_port: &str) -> Result<(), ()> {
let result;
{
// has_host implies !cannot_be_a_base
let scheme = url.scheme();
if !url.has_host() || scheme == "file" {
return Err(())
}
result = Parser::parse_port(Input::new(new_port), || default_port(scheme), Context::Setter)
}
if let Ok((new_port, _remaining)) = result {
url.set_port_internal(new_port);
Ok(())
} else {
Err(())
}
}
/// Getter for https://url.spec.whatwg.org/#dom-url-pathname
#[inline]
pub fn pathname(url: &Url) -> &str {
url.path()
}
/// Setter for https://url.spec.whatwg.org/#dom-url-pathname
pub fn set_pathname(url: &mut Url, new_pathname: &str) {
if !url.cannot_be_a_base() {
url.set_path(new_pathname)
}
}
/// Getter for https://url.spec.whatwg.org/#dom-url-search
pub fn search(url: &Url) -> &str {
trim(&url[Position::AfterPath..Position::AfterQuery])
}
/// Setter for https://url.spec.whatwg.org/#dom-url-search
pub fn set_search(url: &mut Url, new_search: &str) {
url.set_query(match new_search {
"" => None,
_ if new_search.starts_with('?') => Some(&new_search[1..]),
_ => Some(new_search),
})
}
/// Getter for https://url.spec.whatwg.org/#dom-url-hash
pub fn hash(url: &Url) -> &str {
trim(&url[Position::AfterQuery..])
}
/// Setter for https://url.spec.whatwg.org/#dom-url-hash
pub fn set_hash(url: &mut Url, new_hash: &str) {
if url.scheme() != "javascript" {
url.set_fragment(match new_hash {
"" => None,
_ if new_hash.starts_with('#') => Some(&new_hash[1..]),
_ => Some(new_hash),
})
}
}
fn trim(s: &str) -> &str {
if s.len() == 1 {
""
} else {
s
}
}

182
third_party/rust/url/src/slicing.rs vendored Normal file
View file

@ -0,0 +1,182 @@
// Copyright 2016 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Index};
use Url;
impl Index<RangeFull> for Url {
type Output = str;
fn index(&self, _: RangeFull) -> &str {
&self.serialization
}
}
impl Index<RangeFrom<Position>> for Url {
type Output = str;
fn index(&self, range: RangeFrom<Position>) -> &str {
&self.serialization[self.index(range.start)..]
}
}
impl Index<RangeTo<Position>> for Url {
type Output = str;
fn index(&self, range: RangeTo<Position>) -> &str {
&self.serialization[..self.index(range.end)]
}
}
impl Index<Range<Position>> for Url {
type Output = str;
fn index(&self, range: Range<Position>) -> &str {
&self.serialization[self.index(range.start)..self.index(range.end)]
}
}
/// Indicates a position within a URL based on its components.
///
/// A range of positions can be used for slicing `Url`:
///
/// ```rust
/// # use url::{Url, Position};
/// # fn something(some_url: Url) {
/// let serialization: &str = &some_url[..];
/// let serialization_without_fragment: &str = &some_url[..Position::AfterQuery];
/// let authority: &str = &some_url[Position::BeforeUsername..Position::AfterPort];
/// let data_url_payload: &str = &some_url[Position::BeforePath..Position::AfterQuery];
/// let scheme_relative: &str = &some_url[Position::BeforeUsername..];
/// # }
/// ```
///
/// In a pseudo-grammar (where `[`…`]?` makes a sub-sequence optional),
/// URL components and delimiters that separate them are:
///
/// ```notrust
/// url =
/// scheme ":"
/// [ "//" [ username [ ":" password ]? "@" ]? host [ ":" port ]? ]?
/// path [ "?" query ]? [ "#" fragment ]?
/// ```
///
/// When a given component is not present,
/// its "before" and "after" position are the same
/// (so that `&some_url[BeforeFoo..AfterFoo]` is the empty string)
/// and component ordering is preserved
/// (so that a missing query "is between" a path and a fragment).
///
/// The end of a component and the start of the next are either the same or separate
/// by a delimiter.
/// (Not that the initial `/` of a path is considered part of the path here, not a delimiter.)
/// For example, `&url[..BeforeFragment]` would include a `#` delimiter (if present in `url`),
/// so `&url[..AfterQuery]` might be desired instead.
///
/// `BeforeScheme` and `AfterFragment` are always the start and end of the entire URL,
/// so `&url[BeforeScheme..X]` is the same as `&url[..X]`
/// and `&url[X..AfterFragment]` is the same as `&url[X..]`.
#[derive(Copy, Clone, Debug)]
pub enum Position {
BeforeScheme,
AfterScheme,
BeforeUsername,
AfterUsername,
BeforePassword,
AfterPassword,
BeforeHost,
AfterHost,
BeforePort,
AfterPort,
BeforePath,
AfterPath,
BeforeQuery,
AfterQuery,
BeforeFragment,
AfterFragment
}
impl Url {
#[inline]
fn index(&self, position: Position) -> usize {
match position {
Position::BeforeScheme => 0,
Position::AfterScheme => self.scheme_end as usize,
Position::BeforeUsername => if self.has_authority() {
self.scheme_end as usize + "://".len()
} else {
debug_assert!(self.byte_at(self.scheme_end) == b':');
debug_assert!(self.scheme_end + ":".len() as u32 == self.username_end);
self.scheme_end as usize + ":".len()
},
Position::AfterUsername => self.username_end as usize,
Position::BeforePassword => if self.has_authority() &&
self.byte_at(self.username_end) == b':' {
self.username_end as usize + ":".len()
} else {
debug_assert!(self.username_end == self.host_start);
self.username_end as usize
},
Position::AfterPassword => if self.has_authority() &&
self.byte_at(self.username_end) == b':' {
debug_assert!(self.byte_at(self.host_start - "@".len() as u32) == b'@');
self.host_start as usize - "@".len()
} else {
debug_assert!(self.username_end == self.host_start);
self.host_start as usize
},
Position::BeforeHost => self.host_start as usize,
Position::AfterHost => self.host_end as usize,
Position::BeforePort => if self.port.is_some() {
debug_assert!(self.byte_at(self.host_end) == b':');
self.host_end as usize + ":".len()
} else {
self.host_end as usize
},
Position::AfterPort => self.path_start as usize,
Position::BeforePath => self.path_start as usize,
Position::AfterPath => match (self.query_start, self.fragment_start) {
(Some(q), _) => q as usize,
(None, Some(f)) => f as usize,
(None, None) => self.serialization.len(),
},
Position::BeforeQuery => match (self.query_start, self.fragment_start) {
(Some(q), _) => {
debug_assert!(self.byte_at(q) == b'?');
q as usize + "?".len()
}
(None, Some(f)) => f as usize,
(None, None) => self.serialization.len(),
},
Position::AfterQuery => match self.fragment_start {
None => self.serialization.len(),
Some(f) => f as usize,
},
Position::BeforeFragment => match self.fragment_start {
Some(f) => {
debug_assert!(self.byte_at(f) == b'#');
f as usize + "#".len()
}
None => self.serialization.len(),
},
Position::AfterFragment => self.serialization.len(),
}
}
}

193
third_party/rust/url/tests/data.rs vendored Normal file
View file

@ -0,0 +1,193 @@
// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Data-driven tests
extern crate rustc_serialize;
extern crate test;
extern crate url;
use rustc_serialize::json::{self, Json};
use url::{Url, quirks};
fn run_parsing(input: String, base: String, expected: Result<ExpectedAttributes, ()>) {
let base = match Url::parse(&base) {
Ok(base) => base,
Err(message) => panic!("Error parsing base {:?}: {}", base, message)
};
let (url, expected) = match (base.join(&input), expected) {
(Ok(url), Ok(expected)) => (url, expected),
(Err(_), Err(())) => return,
(Err(message), Ok(_)) => panic!("Error parsing URL {:?}: {}", input, message),
(Ok(_), Err(())) => panic!("Expected a parse error for URL {:?}", input),
};
url.assert_invariants();
macro_rules! assert_eq {
($expected: expr, $got: expr) => {
{
let expected = $expected;
let got = $got;
assert!(expected == got, "{:?} != {} {:?} for URL {:?}",
got, stringify!($expected), expected, url);
}
}
}
macro_rules! assert_attributes {
($($attr: ident)+) => {
{
$(
assert_eq!(expected.$attr, quirks::$attr(&url));
)+;
}
}
}
assert_attributes!(href protocol username password host hostname port pathname search hash);
if let Some(expected_origin) = expected.origin {
assert_eq!(expected_origin, quirks::origin(&url));
}
}
struct ExpectedAttributes {
href: String,
origin: Option<String>,
protocol: String,
username: String,
password: String,
host: String,
hostname: String,
port: String,
pathname: String,
search: String,
hash: String,
}
trait JsonExt {
fn take(&mut self, key: &str) -> Option<Json>;
fn object(self) -> json::Object;
fn string(self) -> String;
fn take_string(&mut self, key: &str) -> String;
}
impl JsonExt for Json {
fn take(&mut self, key: &str) -> Option<Json> {
self.as_object_mut().unwrap().remove(key)
}
fn object(self) -> json::Object {
if let Json::Object(o) = self { o } else { panic!("Not a Json::Object") }
}
fn string(self) -> String {
if let Json::String(s) = self { s } else { panic!("Not a Json::String") }
}
fn take_string(&mut self, key: &str) -> String {
self.take(key).unwrap().string()
}
}
fn collect_parsing<F: FnMut(String, test::TestFn)>(add_test: &mut F) {
// Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
let mut json = Json::from_str(include_str!("urltestdata.json"))
.expect("JSON parse error in urltestdata.json");
for entry in json.as_array_mut().unwrap() {
if entry.is_string() {
continue // ignore comments
}
let base = entry.take_string("base");
let input = entry.take_string("input");
let expected = if entry.find("failure").is_some() {
Err(())
} else {
Ok(ExpectedAttributes {
href: entry.take_string("href"),
origin: entry.take("origin").map(Json::string),
protocol: entry.take_string("protocol"),
username: entry.take_string("username"),
password: entry.take_string("password"),
host: entry.take_string("host"),
hostname: entry.take_string("hostname"),
port: entry.take_string("port"),
pathname: entry.take_string("pathname"),
search: entry.take_string("search"),
hash: entry.take_string("hash"),
})
};
add_test(format!("{:?} @ base {:?}", input, base),
test::TestFn::dyn_test_fn(move || run_parsing(input, base, expected)));
}
}
fn collect_setters<F>(add_test: &mut F) where F: FnMut(String, test::TestFn) {
let mut json = Json::from_str(include_str!("setters_tests.json"))
.expect("JSON parse error in setters_tests.json");
macro_rules! setter {
($attr: expr, $setter: ident) => {{
let mut tests = json.take($attr).unwrap();
for mut test in tests.as_array_mut().unwrap().drain(..) {
let comment = test.take("comment").map(Json::string).unwrap_or(String::new());
let href = test.take_string("href");
let new_value = test.take_string("new_value");
let name = format!("{:?}.{} = {:?} {}", href, $attr, new_value, comment);
let mut expected = test.take("expected").unwrap();
add_test(name, test::TestFn::dyn_test_fn(move || {
let mut url = Url::parse(&href).unwrap();
url.assert_invariants();
let _ = quirks::$setter(&mut url, &new_value);
assert_attributes!(url, expected,
href protocol username password host hostname port pathname search hash);
url.assert_invariants();
}))
}
}}
}
macro_rules! assert_attributes {
($url: expr, $expected: expr, $($attr: ident)+) => {
$(
if let Some(value) = $expected.take(stringify!($attr)) {
assert_eq!(quirks::$attr(&$url), value.string())
}
)+
}
}
setter!("protocol", set_protocol);
setter!("username", set_username);
setter!("password", set_password);
setter!("hostname", set_hostname);
setter!("host", set_host);
setter!("port", set_port);
setter!("pathname", set_pathname);
setter!("search", set_search);
setter!("hash", set_hash);
}
fn main() {
let mut tests = Vec::new();
{
let mut add_one = |name: String, run: test::TestFn| {
tests.push(test::TestDescAndFn {
desc: test::TestDesc {
name: test::DynTestName(name),
ignore: false,
should_panic: test::ShouldPanic::No,
},
testfn: run,
})
};
collect_parsing(&mut add_one);
collect_setters(&mut add_one);
}
test::test_main(&std::env::args().collect::<Vec<_>>(), tests)
}

File diff suppressed because it is too large Load diff

303
third_party/rust/url/tests/unit.rs vendored Normal file
View file

@ -0,0 +1,303 @@
// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Unit tests
extern crate url;
use std::borrow::Cow;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::{Path, PathBuf};
use url::{Host, Url, form_urlencoded};
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)));
}};
}
#[test]
fn new_file_paths() {
if cfg!(unix) {
assert_eq!(Url::from_file_path(Path::new("relative")), Err(()));
assert_eq!(Url::from_file_path(Path::new("../relative")), Err(()));
}
if cfg!(windows) {
assert_eq!(Url::from_file_path(Path::new("relative")), Err(()));
assert_eq!(Url::from_file_path(Path::new(r"..\relative")), Err(()));
assert_eq!(Url::from_file_path(Path::new(r"\drive-relative")), Err(()));
assert_eq!(Url::from_file_path(Path::new(r"\\ucn\")), Err(()));
}
if cfg!(unix) {
assert_from_file_path!("/foo/bar");
assert_from_file_path!("/foo/ba\0r", "/foo/ba%00r");
assert_from_file_path!("/foo/ba%00r", "/foo/ba%2500r");
}
}
#[test]
#[cfg(unix)]
fn new_path_bad_utf8() {
use std::ffi::OsStr;
use std::os::unix::prelude::*;
let url = Url::from_file_path(Path::new(OsStr::from_bytes(b"/foo/ba\x80r"))).unwrap();
let os_str = OsStr::from_bytes(b"/foo/ba\x80r");
assert_eq!(url.to_file_path(), Ok(PathBuf::from(os_str)));
}
#[test]
fn new_path_windows_fun() {
if cfg!(windows) {
assert_from_file_path!(r"C:\foo\bar", "/C:/foo/bar");
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());
}
}
#[test]
fn new_directory_paths() {
if cfg!(unix) {
assert_eq!(Url::from_directory_path(Path::new("relative")), Err(()));
assert_eq!(Url::from_directory_path(Path::new("../relative")), Err(()));
let url = Url::from_directory_path(Path::new("/foo/bar")).unwrap();
assert_eq!(url.host(), None);
assert_eq!(url.path(), "/foo/bar/");
}
if cfg!(windows) {
assert_eq!(Url::from_directory_path(Path::new("relative")), Err(()));
assert_eq!(Url::from_directory_path(Path::new(r"..\relative")), Err(()));
assert_eq!(Url::from_directory_path(Path::new(r"\drive-relative")), Err(()));
assert_eq!(Url::from_directory_path(Path::new(r"\\ucn\")), Err(()));
let url = Url::from_directory_path(Path::new(r"C:\foo\bar")).unwrap();
assert_eq!(url.host(), None);
assert_eq!(url.path(), "/C:/foo/bar/");
}
}
#[test]
fn from_str() {
assert!("http://testing.com/this".parse::<Url>().is_ok());
}
#[test]
fn issue_124() {
let url: Url = "file:a".parse().unwrap();
assert_eq!(url.path(), "/a");
let url: Url = "file:...".parse().unwrap();
assert_eq!(url.path(), "/...");
let url: Url = "file:..".parse().unwrap();
assert_eq!(url.path(), "/");
}
#[test]
fn test_equality() {
use std::hash::{Hash, Hasher, SipHasher};
fn check_eq(a: &Url, b: &Url) {
assert_eq!(a, b);
let mut h1 = SipHasher::new();
a.hash(&mut h1);
let mut h2 = SipHasher::new();
b.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish());
}
fn url(s: &str) -> Url {
let rv = s.parse().unwrap();
check_eq(&rv, &rv);
rv
}
// Doesn't care if default port is given.
let a: Url = url("https://example.com/");
let b: Url = url("https://example.com:443/");
check_eq(&a, &b);
// Different ports
let a: Url = url("http://example.com/");
let b: Url = url("http://example.com:8080/");
assert!(a != b, "{:?} != {:?}", a, b);
// Different scheme
let a: Url = url("http://example.com/");
let b: Url = url("https://example.com/");
assert!(a != b);
// Different host
let a: Url = url("http://foo.com/");
let b: Url = url("http://bar.com/");
assert!(a != b);
// Missing path, automatically substituted. Semantically the same.
let a: Url = url("http://foo.com");
let b: Url = url("http://foo.com/");
check_eq(&a, &b);
}
#[test]
fn host() {
fn assert_host(input: &str, host: Host<&str>) {
assert_eq!(Url::parse(input).unwrap().host(), Some(host));
}
assert_host("http://www.mozilla.org", Host::Domain("www.mozilla.org"));
assert_host("http://1.35.33.49", Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49)));
assert_host("http://[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]", Host::Ipv6(Ipv6Addr::new(
0x2001, 0x0db8, 0x85a3, 0x08d3, 0x1319, 0x8a2e, 0x0370, 0x7344)));
assert_host("http://1.35.+33.49", Host::Domain("1.35.+33.49"));
assert_host("http://[::]", Host::Ipv6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)));
assert_host("http://[::1]", Host::Ipv6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)));
assert_host("http://0x1.0X23.0x21.061", Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49)));
assert_host("http://0x1232131", Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49)));
assert_host("http://111", Host::Ipv4(Ipv4Addr::new(0, 0, 0, 111)));
assert_host("http://2..2.3", Host::Domain("2..2.3"));
assert!(Url::parse("http://42.0x1232131").is_err());
assert!(Url::parse("http://192.168.0.257").is_err());
}
#[test]
fn host_serialization() {
// libstd’s `Display for Ipv6Addr` serializes 0:0:0:0:0:0:_:_ and 0:0:0:0:0:ffff:_:_
// using IPv4-like syntax, as suggested in https://tools.ietf.org/html/rfc5952#section-4
// but https://url.spec.whatwg.org/#concept-ipv6-serializer specifies not to.
// Not [::0.0.0.2] / [::ffff:0.0.0.2]
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")));
}
#[test]
fn test_serialization() {
let data = [
("http://example.com/", "http://example.com/"),
("http://addslash.com", "http://addslash.com/"),
("http://@emptyuser.com/", "http://emptyuser.com/"),
("http://:@emptypass.com/", "http://:@emptypass.com/"),
("http://user@user.com/", "http://user@user.com/"),
("http://user:pass@userpass.com/", "http://user:pass@userpass.com/"),
("http://slashquery.com/path/?q=something", "http://slashquery.com/path/?q=something"),
("http://noslashquery.com/path?q=something", "http://noslashquery.com/path?q=something")
];
for &(input, result) in &data {
let url = Url::parse(input).unwrap();
assert_eq!(url.as_str(), result);
}
}
#[test]
fn test_form_urlencoded() {
let pairs: &[(Cow<str>, Cow<str>)] = &[
("foo".into(), "é&".into()),
("bar".into(), "".into()),
("foo".into(), "#".into())
];
let encoded = form_urlencoded::Serializer::new(String::new()).extend_pairs(pairs).finish();
assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23");
assert_eq!(form_urlencoded::parse(encoded.as_bytes()).collect::<Vec<_>>(), pairs.to_vec());
}
#[test]
fn test_form_serialize() {
let encoded = form_urlencoded::Serializer::new(String::new())
.append_pair("foo", "é&")
.append_pair("bar", "")
.append_pair("foo", "#")
.finish();
assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23");
}
#[test]
/// https://github.com/servo/rust-url/issues/25
fn issue_25() {
let filename = if cfg!(windows) { r"C:\run\pg.sock" } else { "/run/pg.sock" };
let mut url = Url::from_file_path(filename).unwrap();
url.assert_invariants();
url.set_scheme("postgres").unwrap();
url.assert_invariants();
url.set_host(Some("")).unwrap();
url.assert_invariants();
url.set_username("me").unwrap();
url.assert_invariants();
let expected = format!("postgres://me@/{}run/pg.sock", if cfg!(windows) { "C:/" } else { "" });
assert_eq!(url.as_str(), expected);
}
#[test]
/// https://github.com/servo/rust-url/issues/61
fn issue_61() {
let mut url = Url::parse("http://mozilla.org").unwrap();
url.set_scheme("https").unwrap();
assert_eq!(url.port(), None);
assert_eq!(url.port_or_known_default(), Some(443));
url.assert_invariants();
}
#[test]
#[cfg(not(windows))]
/// https://github.com/servo/rust-url/issues/197
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]
/// 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");
}
#[test]
/// https://github.com/servo/rust-url/issues/227
fn extend_query_pairs_then_mutate() {
let mut url: Url = "http://localhost:6767/foo/bar".parse().unwrap();
url.query_pairs_mut().extend_pairs(vec![ ("auth", "my-token") ].into_iter());
url.assert_invariants();
assert_eq!(url.to_string(), "http://localhost:6767/foo/bar?auth=my-token");
url.path_segments_mut().unwrap().push("some_other_path");
url.assert_invariants();
assert_eq!(url.to_string(), "http://localhost:6767/foo/bar/some_other_path?auth=my-token");
}
#[test]
/// 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");
}

File diff suppressed because it is too large Load diff