Bug 1444151 - Part 5: Update rust-url to 1.7.0, r=valentin

This commit is contained in:
Nika Layzell 2018-03-09 15:42:17 -05:00
Родитель da7423dfa5
Коммит 6d83ce8024
15 изменённых файлов: 2562 добавлений и 252 удалений

10
Cargo.lock сгенерированный
Просмотреть файл

@ -901,7 +901,7 @@ dependencies = [
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1269,7 +1269,7 @@ version = "0.0.1"
dependencies = [
"nserror 0.1.0",
"nsstring 0.1.0",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"xpcom 0.1.0",
]
@ -2194,7 +2194,7 @@ dependencies = [
[[package]]
name = "url"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2256,7 +2256,7 @@ dependencies = [
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2663,7 +2663,7 @@ dependencies = [
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "78c590b5bd79ed10aad8fb75f078a59d8db445af6c743e55c4a53227fc01c13f"
"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"

2
third_party/rust/url/.cargo-checksum.json поставляемый
Просмотреть файл

@ -1 +1 @@
{"files":{".travis.yml":"890af214187ffcba4732acb2d1af30d7adb9aade0679e9fdb06baae363240b8e","Cargo.toml":"52e8e0a7014d3b0c654491184e9fc82f8c61ba7f51332e2b6a787330be42a301","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e","Makefile":"bffd75d34654b2955d4f005f1a5e85c821c90becf1a8a52cbe10121972f43148","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":"f3e109ca8ec5a9130da50cdfb3003530aedb6dd5a440f0790d76b71f6981119c","src/form_urlencoded.rs":"320418526c4564a4469581d426e7467bcefe504eecd098e1eb90a2663a75fd80","src/host.rs":"4c74946777d76e9b307604f8e24a3485fd0856b664450194e8b429e262cf410d","src/lib.rs":"894cc76c31357fb588292e990a87f4e951043e32ea3d9f38fddc145302d0b318","src/origin.rs":"6e4821eb9600a32ef54d05c8e1a7937f6d9b4dd1e3bda7f36c7988f6a2bef78b","src/parser.rs":"e379c9eb51cff977b9cef368ab64bcff7626e885b859772ab1bc76c9193e9fde","src/path_segments.rs":"7bd3142eaa568863ef44e2255c181239141f9eeee337f889b9ffaaeab4ca669d","src/quirks.rs":"fe6095104cf583053ab35d8a2a093a8581da083641e32d1c5acfe322a26c4bde","src/slicing.rs":"4e539886b23945a92094625f3e531a4bff40daa44240b5d19ee8577478c4f7fe","tests/data.rs":"50a110e475b1717fdaff6524be7d8916cb41a45461e0715f632ff54d0ce28886","tests/setters_tests.json":"ebcbdb52e9a4b5a565f8806d52ebc610d46a34df883e10b0be080d026468ff73","tests/unit.rs":"c0305ca991b2c03815aac2e69ef1c1792b087df92272a6196eb698b27625321f","tests/urltestdata.json":"df87028e1eaea4ef70cf1c1faaed2584e81a46b8b6cd90f50d47b77726ece41c"},"package":"fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"}
{"files":{".travis.yml":"f1183facdda0bd8d7ed7c4fed656b074f3c1dbfc53653dba99293edea0888e7a","Cargo.toml":"0c9e7c23f4216471a535938d0babb4c30595c0ed747ef208da3f042027a3b55b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e","README.md":"eb3f4694003f408cbe3c7f3e9fbbc71241defb940cc55a816981f0f0f144c8eb","UPGRADING.md":"fbcc2d39bdf17db0745793db6626fcd5c909dddd4ce13b27566cfabece22c368","appveyor.yml":"c78486dbfbe6ebbf3d808afb9a19f7ec18c4704ce451c6305f0716999b70a1a6","docs/.nojekyll":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","docs/404.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","docs/index.html":"f61e6271c1ea1aa113b64b356e994595fa548f0433f89948d747503ad22195cd","src/encoding.rs":"f3e109ca8ec5a9130da50cdfb3003530aedb6dd5a440f0790d76b71f6981119c","src/form_urlencoded.rs":"320418526c4564a4469581d426e7467bcefe504eecd098e1eb90a2663a75fd80","src/host.rs":"66a2c0c77a8add2da16bc690fbc82b130cf1367ac655fc36990a214e193a4d6c","src/lib.rs":"899d5741dc0da32cea327f11e10bd2f83722c854f946b7201aae4f6c12edc477","src/origin.rs":"6e4821eb9600a32ef54d05c8e1a7937f6d9b4dd1e3bda7f36c7988f6a2bef78b","src/parser.rs":"91882bcf1dc87c98b2849fe2cecfcbcfa9e478dd39e07b7c029269c98e613163","src/path_segments.rs":"7bd3142eaa568863ef44e2255c181239141f9eeee337f889b9ffaaeab4ca669d","src/quirks.rs":"6cf1697bad363532cbcc60917a9b126560ac3ab3e1a77da0abcf4f2a40c8233a","src/slicing.rs":"4e539886b23945a92094625f3e531a4bff40daa44240b5d19ee8577478c4f7fe","tests/data.rs":"e95a78cadbe156597938057b7048d0d0ac4d3568ca548c0658fbea88d71f2de1","tests/setters_tests.json":"08ddaa632ad19c81e83b904bfaa94bc971f26e2bdfcef27d2f93fd033ad57340","tests/unit.rs":"fb17881a57aab4d369cdbcbb4d062083fc2b80319187fe0040891d2830de22fe","tests/urltestdata.json":"1b0c7c727d8d7e79dfb0d0aa347ff05675ddb68bc4ead38f83fd8e89bc59cc32"},"package":"f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"}

32
third_party/rust/url/.travis.yml поставляемый
Просмотреть файл

@ -1,9 +1,29 @@
language: rust
rust:
- nightly
- beta
- stable
- 1.17.0
script: make test
jobs:
include:
- rust: 1.17.0
install:
# --precise requires Cargo.lock to already exist
- cargo update
# getopts is only used in tests. Its versions 0.2.16+ dont build on 1.17.0
- cargo update -p getopts --precise 0.2.15
# data-url uses pub(crate) which is unstable in 1.17
script: cargo test --all-features -p url -p idna -p percent-encoding -p url_serde
- rust: stable
script: cargo test --all-features --all
- rust: beta
script: cargo test --all-features --all
- rust: nightly
script: cargo test --all-features --all
- rust: nightly
env: TARGET=WASM32 # For job list UI
install: rustup target add wasm32-unknown-unknown
script: cargo build --all --target=wasm32-unknown-unknown
notifications:
webhooks: http://build.servo.org:54856/travis

48
third_party/rust/url/Cargo.toml поставляемый
Просмотреть файл

@ -12,7 +12,7 @@
[package]
name = "url"
version = "1.6.0"
version = "1.7.0"
authors = ["The rust-url developers"]
description = "URL library for Rust, based on the WHATWG URL Standard"
documentation = "https://docs.rs/url"
@ -21,6 +21,8 @@ keywords = ["url", "parser"]
categories = ["parser-implementations", "web-programming", "encoding"]
license = "MIT/Apache-2.0"
repository = "https://github.com/servo/rust-url"
[package.metadata.docs.rs]
features = ["query_encoding"]
[lib]
test = false
@ -31,44 +33,44 @@ name = "unit"
[[test]]
name = "data"
harness = false
[dependencies.rustc-serialize]
version = "0.3"
optional = true
[dependencies.matches]
version = "0.1"
[dependencies.serde]
version = ">=0.6.1, <0.9"
optional = true
[dependencies.percent-encoding]
version = "1.0.0"
[dependencies.encoding]
version = "0.2"
optional = true
[dependencies.heapsize]
version = ">=0.4.1, <0.5"
optional = true
[dependencies.idna]
version = "0.1.0"
[dependencies.heapsize]
version = ">=0.4.1, <0.5"
optional = true
[dev-dependencies.rustc-test]
version = "0.2"
[dependencies.matches]
version = "0.1"
[dependencies.percent-encoding]
version = "1.0.0"
[dependencies.rustc-serialize]
version = "0.3"
optional = true
[dependencies.serde]
version = ">=0.6.1, <0.9"
optional = true
[dev-dependencies.rustc-serialize]
version = "0.3"
[dev-dependencies.rustc-test]
version = "0.2"
[dev-dependencies.serde_json]
version = ">=0.6.1, <0.9"
[features]
heap_size = ["heapsize"]
query_encoding = ["encoding"]
[badges.travis-ci]
repository = "servo/rust-url"
[badges.appveyor]
repository = "Manishearth/rust-url"
[badges.travis-ci]
repository = "servo/rust-url"

6
third_party/rust/url/Makefile поставляемый
Просмотреть файл

@ -1,6 +0,0 @@
test:
cargo test --features "query_encoding serde rustc-serialize heapsize"
(cd idna && cargo test)
(cd url_serde && cargo test)
.PHONY: test

Двоичные данные
third_party/rust/url/github.png поставляемый

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 7.6 KiB

14
third_party/rust/url/rust-url-todo поставляемый
Просмотреть файл

@ -1,14 +0,0 @@
* standalone path parsing?
* Test setters
* Test trim C0/space
* Test remove tab & newline
#[test]
fn test_path_segments() {
let mut url = Url::parse("http://example.net").unwrap();
url.push_path_segment("foo").unwrap();
url.extend_path_segments(&["bar", "b/az"]).unwrap();
assert_eq!(url.as_str(), "http://example.net/foo");
}

61
third_party/rust/url/src/host.rs поставляемый
Просмотреть файл

@ -13,7 +13,7 @@ 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 percent_encoding::{percent_decode, utf8_percent_encode, SIMPLE_ENCODE_SET};
use idna;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -73,7 +73,9 @@ impl<S> From<Host<S>> for HostInternal {
#[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.
/// Non-ASCII labels are encoded in punycode per IDNA if this is the host of
/// a special URL, or percent encoded for non-special URLs. Hosts for
/// non-special URLs are also called opaque hosts.
Domain(S),
/// An IPv4 address.
@ -158,6 +160,23 @@ impl Host<String> {
Ok(Host::Domain(domain.into()))
}
}
// <https://url.spec.whatwg.org/#concept-opaque-host-parser>
pub fn parse_opaque(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)
}
if input.find(|c| matches!(c,
'\0' | '\t' | '\n' | '\r' | ' ' | '#' | '/' | ':' | '?' | '@' | '[' | '\\' | ']'
)).is_some() {
return Err(ParseError::InvalidDomainCharacter)
}
let s = utf8_percent_encode(input, SIMPLE_ENCODE_SET).to_string();
Ok(Host::Domain(s))
}
}
impl<S: AsRef<str>> fmt::Display for Host<S> {
@ -310,7 +329,7 @@ fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) {
}
/// <https://url.spec.whatwg.org/#ipv4-number-parser>
fn parse_ipv4number(mut input: &str) -> Result<u32, ()> {
fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> {
let mut r = 10;
if input.starts_with("0x") || input.starts_with("0X") {
input = &input[2..];
@ -319,14 +338,30 @@ fn parse_ipv4number(mut input: &str) -> Result<u32, ()> {
input = &input[1..];
r = 8;
}
// At the moment we can't know the reason why from_str_radix fails
// https://github.com/rust-lang/rust/issues/22639
// So instead we check if the input looks like a real number and only return
// an error when it's an overflow.
let valid_number = match r {
8 => input.chars().all(|c| c >= '0' && c <='7'),
10 => input.chars().all(|c| c >= '0' && c <='9'),
16 => input.chars().all(|c| (c >= '0' && c <='9') || (c >='a' && c <= 'f') || (c >= 'A' && c <= 'F')),
_ => false
};
if !valid_number {
return Ok(None);
}
if input.is_empty() {
return Ok(0);
return Ok(Some(0));
}
if input.starts_with('+') {
return Err(())
return Ok(None);
}
match u32::from_str_radix(input, r) {
Ok(number) => Ok(number),
Ok(number) => Ok(Some(number)),
Err(_) => Err(()),
}
}
@ -344,15 +379,19 @@ fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> {
return Ok(None);
}
let mut numbers: Vec<u32> = Vec::new();
let mut overflow = false;
for part in parts {
if part == "" {
return Ok(None);
}
if let Ok(n) = parse_ipv4number(part) {
numbers.push(n);
} else {
return Ok(None);
}
match parse_ipv4number(part) {
Ok(Some(n)) => numbers.push(n),
Ok(None) => return Ok(None),
Err(()) => overflow = true
};
}
if overflow {
return Err(ParseError::InvalidIpv4Address);
}
let mut ipv4 = numbers.pop().expect("a non-empty list of numbers");
// Equivalent to: ipv4 >= 256 ** (4 numbers.len())

114
third_party/rust/url/src/lib.rs поставляемый
Просмотреть файл

@ -104,7 +104,7 @@ assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css");
# run().unwrap();
*/
#![doc(html_root_url = "https://docs.rs/url/1.6.0")]
#![doc(html_root_url = "https://docs.rs/url/1.7.0")]
#[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
#[macro_use] extern crate matches;
@ -117,7 +117,7 @@ pub extern crate percent_encoding;
use encoding::EncodingOverride;
#[cfg(feature = "heapsize")] use heapsize::HeapSizeOf;
use host::HostInternal;
use parser::{Parser, Context, SchemeType, to_u32};
use parser::{Parser, Context, SchemeType, to_u32, ViolationFn};
use percent_encoding::{PATH_SEGMENT_ENCODE_SET, USERINFO_ENCODE_SET,
percent_encode, percent_decode, utf8_percent_encode};
use std::borrow::Borrow;
@ -135,7 +135,7 @@ use std::str;
pub use origin::{Origin, OpaqueOrigin};
pub use host::{Host, HostAndPort, SocketAddrs};
pub use path_segments::PathSegmentsMut;
pub use parser::ParseError;
pub use parser::{ParseError, SyntaxViolation};
pub use slicing::Position;
mod encoding;
@ -186,7 +186,7 @@ impl HeapSizeOf for Url {
pub struct ParseOptions<'a> {
base_url: Option<&'a Url>,
encoding_override: encoding::EncodingOverride,
log_syntax_violation: Option<&'a Fn(&'static str)>,
violation_fn: ViolationFn<'a>,
}
impl<'a> ParseOptions<'a> {
@ -209,9 +209,47 @@ impl<'a> ParseOptions<'a> {
self
}
/// Call the provided function or closure on non-fatal parse errors.
/// Call the provided function or closure on non-fatal parse errors, passing
/// a static string description. This method is deprecated in favor of
/// `syntax_violation_callback` and is implemented as an adaptor for the
/// latter, passing the `SyntaxViolation` description. Only the last value
/// passed to either method will be used by a parser.
#[deprecated]
pub fn log_syntax_violation(mut self, new: Option<&'a Fn(&'static str)>) -> Self {
self.log_syntax_violation = new;
self.violation_fn = match new {
Some(f) => ViolationFn::OldFn(f),
None => ViolationFn::NoOp
};
self
}
/// Call the provided function or closure for a non-fatal `SyntaxViolation`
/// when it occurs during parsing. Note that since the provided function is
/// `Fn`, the caller might need to utilize _interior mutability_, such as with
/// a `RefCell`, to collect the violations.
///
/// ## Example
/// ```
/// use std::cell::RefCell;
/// use url::{Url, SyntaxViolation};
/// # use url::ParseError;
/// # fn run() -> Result<(), url::ParseError> {
/// let violations = RefCell::new(Vec::new());
/// let url = Url::options()
/// .syntax_violation_callback(Some(&|v| violations.borrow_mut().push(v)))
/// .parse("https:////example.com")?;
/// assert_eq!(url.as_str(), "https://example.com/");
/// assert_eq!(violations.into_inner(),
/// vec!(SyntaxViolation::ExpectedDoubleSlash));
/// # Ok(())
/// # }
/// # run().unwrap();
/// ```
pub fn syntax_violation_callback(mut self, new: Option<&'a Fn(SyntaxViolation)>) -> Self {
self.violation_fn = match new {
Some(f) => ViolationFn::NewFn(f),
None => ViolationFn::NoOp
};
self
}
@ -221,7 +259,7 @@ impl<'a> ParseOptions<'a> {
serialization: String::with_capacity(input.len()),
base_url: self.base_url,
query_encoding_override: self.encoding_override,
log_syntax_violation: self.log_syntax_violation,
violation_fn: self.violation_fn,
context: Context::UrlParser,
}.parse_url(input)
}
@ -229,11 +267,12 @@ impl<'a> ParseOptions<'a> {
impl<'a> Debug for ParseOptions<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "ParseOptions {{ base_url: {:?}, encoding_override: {:?}, log_syntax_violation: ", self.base_url, self.encoding_override)?;
match self.log_syntax_violation {
Some(_) => write!(f, "Some(Fn(&'static str)) }}"),
None => write!(f, "None }}")
}
write!(f,
"ParseOptions {{ base_url: {:?}, encoding_override: {:?}, \
violation_fn: {:?} }}",
self.base_url,
self.encoding_override,
self.violation_fn)
}
}
@ -252,7 +291,7 @@ impl Url {
/// # }
/// # run().unwrap();
/// ```
///
///
/// # Errors
///
/// If the function can not parse an absolute URL from the given string,
@ -315,7 +354,7 @@ impl Url {
/// ```rust
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let base = Url::parse("https://example.net/a/b.html")?;
/// let url = base.join("c.png")?;
@ -331,7 +370,7 @@ impl Url {
///
/// # Errors
///
/// If the function can not parse an URL from the given string
/// If the function can not parse an URL from the given string
/// with this URL as the base URL, a [`ParseError`] variant will be returned.
///
/// [`ParseError`]: enum.ParseError.html
@ -363,7 +402,7 @@ impl Url {
ParseOptions {
base_url: None,
encoding_override: EncodingOverride::utf8(),
log_syntax_violation: None,
violation_fn: ViolationFn::NoOp,
}
}
@ -1177,11 +1216,11 @@ impl Url {
/// assert_eq!(url.as_str(), "https://example.com/data.csv");
/// url.set_fragment(Some("cell=4,1-6,2"));
/// assert_eq!(url.as_str(), "https://example.com/data.csv#cell=4,1-6,2");
/// assert_eq!(url.as_str(), "https://example.com/data.csv#cell=4,1-6,2");
/// assert_eq!(url.fragment(), Some("cell=4,1-6,2"));
///
/// url.set_fragment(None);
/// assert_eq!(url.as_str(), "https://example.com/data.csv");
/// assert_eq!(url.as_str(), "https://example.com/data.csv");
/// assert!(url.fragment().is_none());
/// # Ok(())
/// # }
@ -1234,7 +1273,7 @@ impl Url {
/// assert_eq!(url.as_str(), "https://example.com/products");
///
/// url.set_query(Some("page=2"));
/// assert_eq!(url.as_str(), "https://example.com/products?page=2");
/// assert_eq!(url.as_str(), "https://example.com/products?page=2");
/// assert_eq!(url.query(), Some("page=2"));
/// # Ok(())
/// # }
@ -1330,12 +1369,12 @@ impl Url {
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("https://example.com")?;
/// url.set_path("api/comments");
/// assert_eq!(url.as_str(), "https://example.com/api/comments");
/// assert_eq!(url.as_str(), "https://example.com/api/comments");
/// assert_eq!(url.path(), "/api/comments");
///
/// let mut url = Url::parse("https://example.com/api")?;
/// url.set_path("data/report.csv");
/// assert_eq!(url.as_str(), "https://example.com/data/report.csv");
/// assert_eq!(url.as_str(), "https://example.com/data/report.csv");
/// assert_eq!(url.path(), "/data/report.csv");
/// # Ok(())
/// # }
@ -1427,7 +1466,8 @@ impl Url {
/// # run().unwrap();
/// ```
pub fn set_port(&mut self, mut port: Option<u16>) -> Result<(), ()> {
if !self.has_host() || self.scheme() == "file" {
// has_host implies !cannot_be_a_base
if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" {
return Err(())
}
if port.is_some() && port == parser::default_port(self.scheme()) {
@ -1495,7 +1535,7 @@ impl Url {
/// ```
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("foo://example.net")?;
/// let result = url.set_host(None);
@ -1511,7 +1551,7 @@ impl Url {
/// ```
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("https://example.net")?;
/// let result = url.set_host(None);
@ -1527,7 +1567,7 @@ impl Url {
/// ```
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("mailto:rms@example.net")?;
///
@ -1558,7 +1598,11 @@ impl Url {
if host == "" && SchemeType::from(self.scheme()).is_special() {
return Err(ParseError::EmptyHost);
}
self.set_host_internal(Host::parse(host)?, None)
if SchemeType::from(self.scheme()).is_special() {
self.set_host_internal(Host::parse(host)?, None)
} else {
self.set_host_internal(Host::parse_opaque(host)?, None)
}
} else if self.has_host() {
if SchemeType::from(self.scheme()).is_special() {
return Err(ParseError::EmptyHost)
@ -1691,7 +1735,8 @@ impl Url {
/// # run().unwrap();
/// ```
pub fn set_password(&mut self, password: Option<&str>) -> Result<(), ()> {
if !self.has_host() {
// has_host implies !cannot_be_a_base
if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" {
return Err(())
}
if let Some(password) = password {
@ -1772,7 +1817,8 @@ impl Url {
/// # run().unwrap();
/// ```
pub fn set_username(&mut self, username: &str) -> Result<(), ()> {
if !self.has_host() {
// has_host implies !cannot_be_a_base
if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" {
return Err(())
}
let username_start = self.scheme_end + 3;
@ -1831,7 +1877,7 @@ impl Url {
/// ```
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("https://example.net")?;
/// let result = url.set_scheme("foo");
@ -1848,7 +1894,7 @@ impl Url {
/// ```
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("https://example.net")?;
/// let result = url.set_scheme("foõ");
@ -1864,7 +1910,7 @@ impl Url {
/// ```
/// use url::Url;
/// # use url::ParseError;
///
///
/// # fn run() -> Result<(), ParseError> {
/// let mut url = Url::parse("mailto:rms@example.net")?;
/// let result = url.set_scheme("https");
@ -1913,7 +1959,7 @@ impl Url {
/// ```
/// # if cfg!(unix) {
/// use url::Url;
///
///
/// # fn run() -> Result<(), ()> {
/// let url = Url::from_file_path("/tmp/foo.txt")?;
/// assert_eq!(url.as_str(), "file:///tmp/foo.txt");
@ -1928,6 +1974,7 @@ impl Url {
/// # run().unwrap();
/// # }
/// ```
#[cfg(any(unix, windows, target_os="redox"))]
pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
let mut serialization = "file://".to_owned();
let host_start = serialization.len() as u32;
@ -1963,6 +2010,7 @@ impl Url {
///
/// Note that `std::path` does not consider trailing slashes significant
/// and usually does not include them (e.g. in `Path::parent()`).
#[cfg(any(unix, windows, target_os="redox"))]
pub fn from_directory_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
let mut url = Url::from_file_path(path)?;
if !url.serialization.ends_with('/') {
@ -2044,6 +2092,7 @@ impl Url {
/// (That is, if the percent-decoded path contains a NUL byte or,
/// for a Windows path, is not UTF-8.)
#[inline]
#[cfg(any(unix, windows, target_os="redox"))]
pub fn to_file_path(&self) -> Result<PathBuf, ()> {
if let Some(segments) = self.path_segments() {
let host = match self.host() {
@ -2290,6 +2339,7 @@ fn path_to_file_url_segments_windows(path: &Path, serialization: &mut String)
Ok((host_end, host_internal))
}
#[cfg(any(unix, target_os = "redox"))]
fn file_url_segments_to_pathbuf(host: Option<&str>, segments: str::Split<char>) -> Result<PathBuf, ()> {
use std::ffi::OsStr;

207
third_party/rust/url/src/parser.rs поставляемый
Просмотреть файл

@ -70,6 +70,54 @@ impl From<::idna::uts46::Errors> for ParseError {
fn from(_: ::idna::uts46::Errors) -> ParseError { ParseError::IdnaError }
}
macro_rules! syntax_violation_enum {
($($name: ident => $description: expr,)+) => {
/// Non-fatal syntax violations that can occur during parsing.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum SyntaxViolation {
$(
$name,
)+
}
impl SyntaxViolation {
pub fn description(&self) -> &'static str {
match *self {
$(
SyntaxViolation::$name => $description,
)+
}
}
}
}
}
syntax_violation_enum! {
Backslash => "backslash",
C0SpaceIgnored =>
"leading or trailing control or space character are ignored in URLs",
EmbeddedCredentials =>
"embedding authentication information (username or password) \
in an URL is not recommended",
ExpectedDoubleSlash => "expected //",
ExpectedFileDoubleSlash => "expected // after file:",
FileWithHostAndWindowsDrive => "file: with host and Windows drive letter",
NonUrlCodePoint => "non-URL code point",
NullInFragment => "NULL characters are ignored in URL fragment identifiers",
PercentDecode => "expected 2 hex digits after %",
TabOrNewlineIgnored => "tabs or newlines are ignored in URLs",
UnencodedAtSign => "unencoded @ sign in username or password",
}
#[cfg(feature = "heapsize")]
known_heap_size!(0, SyntaxViolation);
impl fmt::Display for SyntaxViolation {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
self.description().fmt(fmt)
}
}
#[derive(Copy, Clone)]
pub enum SchemeType {
File,
@ -112,18 +160,17 @@ pub struct Input<'i> {
impl<'i> Input<'i> {
pub fn new(input: &'i str) -> Self {
Input::with_log(input, None)
Input::with_log(input, ViolationFn::NoOp)
}
pub fn with_log(original_input: &'i str, log_syntax_violation: Option<&Fn(&'static str)>)
-> Self {
pub fn with_log(original_input: &'i str, vfn: ViolationFn) -> Self {
let input = original_input.trim_matches(c0_control_or_space);
if let Some(log) = log_syntax_violation {
if vfn.is_set() {
if input.len() < original_input.len() {
log("leading or trailing control or space character are ignored in URLs")
vfn.call(SyntaxViolation::C0SpaceIgnored)
}
if input.chars().any(|c| matches!(c, '\t' | '\n' | '\r')) {
log("tabs or newlines are ignored in URLs")
vfn.call(SyntaxViolation::TabOrNewlineIgnored)
}
}
Input { chars: input.chars() }
@ -216,11 +263,60 @@ impl<'i> Iterator for Input<'i> {
}
}
/// Wrapper for syntax violation callback functions.
#[derive(Copy, Clone)]
pub enum ViolationFn<'a> {
NewFn(&'a (Fn(SyntaxViolation) + 'a)),
OldFn(&'a (Fn(&'static str) + 'a)),
NoOp
}
impl<'a> ViolationFn<'a> {
/// Call with a violation.
pub fn call(self, v: SyntaxViolation) {
match self {
ViolationFn::NewFn(f) => f(v),
ViolationFn::OldFn(f) => f(v.description()),
ViolationFn::NoOp => {}
}
}
/// Call with a violation, if provided test returns true. Avoids
/// the test entirely if `NoOp`.
pub fn call_if<F>(self, v: SyntaxViolation, test: F)
where F: Fn() -> bool
{
match self {
ViolationFn::NewFn(f) => if test() { f(v) },
ViolationFn::OldFn(f) => if test() { f(v.description()) },
ViolationFn::NoOp => {} // avoid test
}
}
/// True if not `NoOp`
pub fn is_set(self) -> bool {
match self {
ViolationFn::NoOp => false,
_ => true
}
}
}
impl<'a> fmt::Debug for ViolationFn<'a> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
ViolationFn::NewFn(_) => write!(f, "NewFn(Fn(SyntaxViolation))"),
ViolationFn::OldFn(_) => write!(f, "OldFn(Fn(&'static str))"),
ViolationFn::NoOp => write!(f, "NoOp")
}
}
}
pub struct Parser<'a> {
pub serialization: String,
pub base_url: Option<&'a Url>,
pub query_encoding_override: EncodingOverride,
pub log_syntax_violation: Option<&'a Fn(&'static str)>,
pub violation_fn: ViolationFn<'a>,
pub context: Context,
}
@ -237,29 +333,14 @@ impl<'a> Parser<'a> {
serialization: serialization,
base_url: None,
query_encoding_override: EncodingOverride::utf8(),
log_syntax_violation: None,
violation_fn: ViolationFn::NoOp,
context: Context::Setter,
}
}
fn syntax_violation(&self, reason: &'static str) {
if let Some(log) = self.log_syntax_violation {
log(reason)
}
}
fn syntax_violation_if<F: Fn() -> bool>(&self, reason: &'static str, test: F) {
// Skip test if not logging.
if let Some(log) = self.log_syntax_violation {
if test() {
log(reason)
}
}
}
/// https://url.spec.whatwg.org/#concept-basic-url-parser
pub fn parse_url(mut self, input: &str) -> ParseResult<Url> {
let input = Input::with_log(input, self.log_syntax_violation);
let input = Input::with_log(input, self.violation_fn);
if let Ok(remaining) = self.parse_scheme(input.clone()) {
return self.parse_with_scheme(remaining)
}
@ -310,12 +391,13 @@ impl<'a> Parser<'a> {
}
fn parse_with_scheme(mut self, input: Input) -> ParseResult<Url> {
use SyntaxViolation::{ExpectedFileDoubleSlash, ExpectedDoubleSlash};
let scheme_end = to_u32(self.serialization.len())?;
let scheme_type = SchemeType::from(&self.serialization);
self.serialization.push(':');
match scheme_type {
SchemeType::File => {
self.syntax_violation_if("expected // after file:", || !input.starts_with("//"));
self.violation_fn.call_if(ExpectedFileDoubleSlash, || !input.starts_with("//"));
let base_file_url = self.base_url.and_then(|base| {
if base.scheme() == "file" { Some(base) } else { None }
});
@ -335,7 +417,7 @@ impl<'a> Parser<'a> {
}
}
// special authority slashes state
self.syntax_violation_if("expected //", || {
self.violation_fn.call_if(ExpectedDoubleSlash, || {
input.clone().take_while(|&c| matches!(c, '/' | '\\'))
.collect::<String>() != "//"
});
@ -371,6 +453,7 @@ impl<'a> Parser<'a> {
}
fn parse_file(mut self, input: Input, mut base_file_url: Option<&Url>) -> ParseResult<Url> {
use SyntaxViolation::Backslash;
// file state
debug_assert!(self.serialization.is_empty());
let (first_char, input_after_first_char) = input.split_first();
@ -451,6 +534,7 @@ impl<'a> Parser<'a> {
let scheme_end = "file".len() as u32;
let path_start = "file://".len() as u32;
let fragment_start = "file:///".len() as u32;
self.serialization.push('#');
self.parse_fragment(input_after_first_char);
Ok(Url {
serialization: self.serialization,
@ -467,18 +551,18 @@ impl<'a> Parser<'a> {
}
}
Some('/') | Some('\\') => {
self.syntax_violation_if("backslash", || first_char == Some('\\'));
self.violation_fn.call_if(Backslash, || first_char == Some('\\'));
// file slash state
let (next_char, input_after_next_char) = input_after_first_char.split_first();
self.syntax_violation_if("backslash", || next_char == Some('\\'));
self.violation_fn.call_if(Backslash, || next_char == Some('\\'));
if matches!(next_char, Some('/') | Some('\\')) {
// file host state
self.serialization.push_str("file://");
let scheme_end = "file".len() as u32;
let host_start = "file://".len() as u32;
let (path_start, host, remaining) =
let (path_start, mut host, remaining) =
self.parse_file_host(input_after_next_char)?;
let host_end = to_u32(self.serialization.len())?;
let mut host_end = to_u32(self.serialization.len())?;
let mut has_host = !matches!(host, HostInternal::None);
let remaining = if path_start {
self.parse_path_start(SchemeType::File, &mut has_host, remaining)
@ -487,7 +571,13 @@ impl<'a> Parser<'a> {
self.serialization.push('/');
self.parse_path(SchemeType::File, &mut has_host, path_start, remaining)
};
// FIXME: deal with has_host
// For file URLs that have a host and whose path starts
// with the windows drive letter we just remove the host.
if !has_host {
self.serialization.drain(host_start as usize..host_end as usize);
host_end = host_start;
host = HostInternal::None;
}
let (query_start, fragment_start) =
self.parse_query_and_fragment(scheme_end, remaining)?;
Ok(Url {
@ -616,7 +706,7 @@ impl<'a> Parser<'a> {
Some('/') | Some('\\') => {
let (slashes_count, remaining) = input.count_matching(|c| matches!(c, '/' | '\\'));
if slashes_count >= 2 {
self.syntax_violation_if("expected //", || {
self.violation_fn.call_if(SyntaxViolation::ExpectedDoubleSlash, || {
input.clone().take_while(|&c| matches!(c, '/' | '\\'))
.collect::<String>() != "//"
});
@ -680,11 +770,9 @@ impl<'a> Parser<'a> {
match c {
'@' => {
if last_at.is_some() {
self.syntax_violation("unencoded @ sign in username or password")
self.violation_fn.call(SyntaxViolation::UnencodedAtSign)
} else {
self.syntax_violation(
"embedding authentication information (username or password) \
in an URL is not recommended")
self.violation_fn.call(SyntaxViolation::EmbeddedCredentials)
}
last_at = Some((char_count, remaining.clone()))
},
@ -701,14 +789,23 @@ impl<'a> Parser<'a> {
};
let mut username_end = None;
let mut has_password = false;
let mut has_username = false;
while userinfo_char_count > 0 {
let (c, utf8_c) = input.next_utf8().unwrap();
userinfo_char_count -= 1;
if c == ':' && username_end.is_none() {
// Start parsing password
username_end = Some(to_u32(self.serialization.len())?);
self.serialization.push(':');
// We don't add a colon if the password is empty
if userinfo_char_count > 0 {
self.serialization.push(':');
has_password = true;
}
} else {
if !has_password {
has_username = true;
}
self.check_url_code_point(c, &input);
self.serialization.extend(utf8_percent_encode(utf8_c, USERINFO_ENCODE_SET));
}
@ -717,7 +814,9 @@ impl<'a> Parser<'a> {
Some(i) => i,
None => to_u32(self.serialization.len())?,
};
self.serialization.push('@');
if has_username || has_password {
self.serialization.push('@');
}
Ok((username_end, remaining))
}
@ -783,6 +882,10 @@ impl<'a> Parser<'a> {
if scheme_type.is_special() && host_str.is_empty() {
return Err(ParseError::EmptyHost)
}
if !scheme_type.is_special() {
let host = Host::parse_opaque(host_str)?;
return Ok((host, input));
}
let host = Host::parse(host_str)?;
Ok((host, input))
}
@ -867,7 +970,7 @@ impl<'a> Parser<'a> {
match input.split_first() {
(Some('/'), remaining) => input = remaining,
(Some('\\'), remaining) => if scheme_type.is_special() {
self.syntax_violation("backslash");
self.violation_fn.call(SyntaxViolation::Backslash);
input = remaining
},
_ => {}
@ -895,7 +998,7 @@ impl<'a> Parser<'a> {
},
'\\' if self.context != Context::PathSegmentSetter &&
scheme_type.is_special() => {
self.syntax_violation("backslash");
self.violation_fn.call(SyntaxViolation::Backslash);
ends_with_slash = true;
break
},
@ -905,15 +1008,6 @@ impl<'a> Parser<'a> {
},
_ => {
self.check_url_code_point(c, &input);
if c == '%' {
let after_percent_sign = input.clone();
if matches!(input.next(), Some('2')) &&
matches!(input.next(), Some('E') | Some('e')) {
self.serialization.push('.');
continue
}
input = after_percent_sign
}
if self.context == Context::PathSegmentSetter {
self.serialization.extend(utf8_percent_encode(
utf8_c, PATH_SEGMENT_ENCODE_SET));
@ -925,7 +1019,7 @@ impl<'a> Parser<'a> {
}
}
match &self.serialization[segment_start..] {
".." => {
".." | "%2e%2e" | "%2e%2E" | "%2E%2e" | "%2E%2E" | "%2e." | "%2E." | ".%2e" | ".%2E" => {
debug_assert!(self.serialization.as_bytes()[segment_start - 1] == b'/');
self.serialization.truncate(segment_start - 1); // Truncate "/.."
self.pop_path(scheme_type, path_start);
@ -933,7 +1027,7 @@ impl<'a> Parser<'a> {
self.serialization.push('/')
}
},
"." => {
"." | "%2e" | "%2E" => {
self.serialization.truncate(segment_start);
},
_ => {
@ -945,7 +1039,7 @@ impl<'a> Parser<'a> {
self.serialization.push(':');
}
if *has_host {
self.syntax_violation("file: with host and Windows drive letter");
self.violation_fn.call(SyntaxViolation::FileWithHostAndWindowsDrive);
*has_host = false; // FIXME account for this in callers
}
}
@ -1087,7 +1181,7 @@ impl<'a> Parser<'a> {
pub fn parse_fragment(&mut self, mut input: Input) {
while let Some((c, utf8_c)) = input.next_utf8() {
if c == '\0' {
self.syntax_violation("NULL characters are ignored in URL fragment identifiers")
self.violation_fn.call(SyntaxViolation::NullInFragment)
} else {
self.check_url_code_point(c, &input);
self.serialization.extend(utf8_percent_encode(utf8_c,
@ -1097,15 +1191,16 @@ impl<'a> Parser<'a> {
}
fn check_url_code_point(&self, c: char, input: &Input) {
if let Some(log) = self.log_syntax_violation {
let vfn = self.violation_fn;
if vfn.is_set() {
if c == '%' {
let mut input = input.clone();
if !matches!((input.next(), input.next()), (Some(a), Some(b))
if is_ascii_hex_digit(a) && is_ascii_hex_digit(b)) {
log("expected 2 hex digits after %")
vfn.call(SyntaxViolation::PercentDecode)
}
} else if !is_url_code_point(c) {
log("non-URL code point")
vfn.call(SyntaxViolation::NonUrlCodePoint)
}
}
}

2
third_party/rust/url/src/quirks.rs поставляемый
Просмотреть файл

@ -152,7 +152,7 @@ pub fn set_port(url: &mut Url, new_port: &str) -> Result<(), ()> {
{
// has_host implies !cannot_be_a_base
let scheme = url.scheme();
if !url.has_host() || scheme == "file" {
if !url.has_host() || url.host() == Some(Host::Domain("")) || scheme == "file" {
return Err(())
}
result = Parser::parse_port(Input::new(new_port), || default_port(scheme), Context::Setter)

1
third_party/rust/url/tests/data.rs поставляемый
Просмотреть файл

@ -29,6 +29,7 @@ fn check_invariants(url: &Url) {
fn run_parsing(input: &str, base: &str, expected: Result<ExpectedAttributes, ()>) {
let base = match Url::parse(&base) {
Ok(base) => base,
Err(_) if expected.is_err() => return,
Err(message) => panic!("Error parsing base {:?}: {}", base, message)
};
let (url, expected) = match (base.join(&input), expected) {

437
third_party/rust/url/tests/setters_tests.json поставляемый
Просмотреть файл

@ -101,6 +101,31 @@
"protocol": "a:"
}
},
{
"comment": "Cant switch from file URL with no host",
"href": "file://localhost/",
"new_value": "http",
"expected": {
"href": "file:///",
"protocol": "file:"
}
},
{
"href": "file:///test",
"new_value": "gopher",
"expected": {
"href": "file:///test",
"protocol": "file:"
}
},
{
"href": "file:",
"new_value": "wss",
"expected": {
"href": "file:///",
"protocol": "file:"
}
},
{
"comment": "Spec deviation: from special scheme to not is not problematic. https://github.com/whatwg/url/issues/104",
"href": "http://example.net",
@ -175,6 +200,14 @@
"username": ""
}
},
{
"href": "javascript:alert(1)",
"new_value": "wario",
"expected": {
"href": "javascript:alert(1)",
"username": ""
}
},
{
"href": "http://example.net",
"new_value": "me",
@ -224,6 +257,30 @@
"href": "http://%c3%89t%C3%A9@example.net/",
"username": "%c3%89t%C3%A9"
}
},
{
"href": "sc:///",
"new_value": "x",
"expected": {
"href": "sc:///",
"username": ""
}
},
{
"href": "file://test/",
"new_value": "test",
"expected": {
"href": "file://test/",
"username": ""
}
},
{
"href": "javascript://x/",
"new_value": "wario",
"expected": {
"href": "javascript://wario@x/",
"username": "wario"
}
}
],
"password": [
@ -303,9 +360,105 @@
"href": "http://:%c3%89t%C3%A9@example.net/",
"password": "%c3%89t%C3%A9"
}
},
{
"href": "sc:///",
"new_value": "x",
"expected": {
"href": "sc:///",
"password": ""
}
},
{
"href": "file://test/",
"new_value": "test",
"expected": {
"href": "file://test/",
"password": ""
}
},
{
"href": "javascript://x/",
"new_value": "bowser",
"expected": {
"href": "javascript://:bowser@x/",
"password": "bowser"
}
}
],
"host": [
{
"href": "sc://x/",
"new_value": "\u0009",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "\u000A",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "\u000D",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "#",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "/",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "?",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "@",
"expected": {
"href": "sc://x/",
"host": "x",
"hostname": "x"
}
},
{
"href": "sc://x/",
"new_value": "ß",
"expected": {
"href": "sc://%C3%9F/",
"host": "%C3%9F",
"hostname": "%C3%9F"
}
},
{
"comment": "Cannot-be-a-base means no host",
"href": "mailto:me@example.net",
@ -383,15 +536,6 @@
"host": "example.net"
}
},
{
"comment": "Path-only URLs can gain a host",
"href": "a:/foo",
"new_value": "example.net",
"expected": {
"href": "a://example.net/foo",
"host": "example.net"
}
},
{
"comment": "IPv4 address syntax is normalized",
"href": "http://example.net",
@ -536,7 +680,7 @@
}
},
{
"comment": "\\ is not a delimiter for non-special schemes, and its invalid in a domain",
"comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
"href": "view-source+http://example.net/path",
"new_value": "example.com\\stuff",
"expected": {
@ -600,9 +744,118 @@
"hostname": "example.com",
"port": ""
}
},
{
"comment": "Broken IPv6",
"href": "http://example.net/",
"new_value": "[google.com]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.2.3.4x]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.2.3.]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.2.]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
}
],
"hostname": [
{
"href": "sc://x/",
"new_value": "\u0009",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "\u000A",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "\u000D",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "#",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "/",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "?",
"expected": {
"href": "sc:///",
"host": "",
"hostname": ""
}
},
{
"href": "sc://x/",
"new_value": "@",
"expected": {
"href": "sc://x/",
"host": "x",
"hostname": "x"
}
},
{
"comment": "Cannot-be-a-base means no host",
"href": "mailto:me@example.net",
@ -658,15 +911,6 @@
"host": "example.net"
}
},
{
"comment": "Path-only URLs can gain a host",
"href": "a:/foo",
"new_value": "example.net",
"expected": {
"href": "a://example.net/foo",
"host": "example.net"
}
},
{
"comment": "IPv4 address syntax is normalized",
"href": "http://example.net:8080",
@ -756,7 +1000,7 @@
}
},
{
"comment": "\\ is not a delimiter for non-special schemes, and its invalid in a domain",
"comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
"href": "view-source+http://example.net/path",
"new_value": "example.com\\stuff",
"expected": {
@ -765,6 +1009,52 @@
"hostname": "example.net",
"port": ""
}
},
{
"comment": "Broken IPv6",
"href": "http://example.net/",
"new_value": "[google.com]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.2.3.4x]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.2.3.]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.2.]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
},
{
"href": "http://example.net/",
"new_value": "[::1.]",
"expected": {
"href": "http://example.net/",
"host": "example.net",
"hostname": "example.net"
}
}
],
"port": [
@ -779,7 +1069,7 @@
}
},
{
"comment": "Port number is removed if empty in the new value: https://github.com/whatwg/url/pull/113",
"comment": "Port number is removed if empty is the new value",
"href": "http://example.net:8080",
"new_value": "",
"expected": {
@ -920,6 +1210,65 @@
"hostname": "example.net",
"port": "8080"
}
},
{
"comment": "Port numbers are 16 bit integers, overflowing is an error",
"href": "non-special://example.net:8080/path",
"new_value": "65536",
"expected": {
"href": "non-special://example.net:8080/path",
"host": "example.net:8080",
"hostname": "example.net",
"port": "8080"
}
},
{
"href": "file://test/",
"new_value": "12",
"expected": {
"href": "file://test/",
"port": ""
}
},
{
"href": "file://localhost/",
"new_value": "12",
"expected": {
"href": "file:///",
"port": ""
}
},
{
"href": "non-base:value",
"new_value": "12",
"expected": {
"href": "non-base:value",
"port": ""
}
},
{
"href": "sc:///",
"new_value": "12",
"expected": {
"href": "sc:///",
"port": ""
}
},
{
"href": "sc://x/",
"new_value": "12",
"expected": {
"href": "sc://x:12/",
"port": "12"
}
},
{
"href": "javascript://x/",
"new_value": "12",
"expected": {
"href": "javascript://x:12/",
"port": "12"
}
}
],
"pathname": [
@ -970,8 +1319,8 @@
"href": "view-source+http://example.net/home?lang=fr#nav",
"new_value": "\\a\\%2E\\b\\%2e.\\c",
"expected": {
"href": "view-source+http://example.net/\\a\\.\\b\\..\\c?lang=fr#nav",
"pathname": "/\\a\\.\\b\\..\\c"
"href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav",
"pathname": "/\\a\\%2E\\b\\%2e.\\c"
}
},
{
@ -984,12 +1333,48 @@
}
},
{
"comment": "Bytes already percent-encoded are left as-is, except %2E.",
"comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.",
"href": "http://example.net",
"new_value": "%2e%2E%c3%89té",
"expected": {
"href": "http://example.net/..%c3%89t%C3%A9",
"pathname": "/..%c3%89t%C3%A9"
"href": "http://example.net/%2e%2E%c3%89t%C3%A9",
"pathname": "/%2e%2E%c3%89t%C3%A9"
}
},
{
"comment": "? needs to be encoded",
"href": "http://example.net",
"new_value": "?",
"expected": {
"href": "http://example.net/%3F",
"pathname": "/%3F"
}
},
{
"comment": "# needs to be encoded",
"href": "http://example.net",
"new_value": "#",
"expected": {
"href": "http://example.net/%23",
"pathname": "/%23"
}
},
{
"comment": "? needs to be encoded, non-special scheme",
"href": "sc://example.net",
"new_value": "?",
"expected": {
"href": "sc://example.net/%3F",
"pathname": "/%3F"
}
},
{
"comment": "# needs to be encoded, non-special scheme",
"href": "sc://example.net",
"new_value": "#",
"expected": {
"href": "sc://example.net/%23",
"pathname": "/%23"
}
}
],

89
third_party/rust/url/tests/unit.rs поставляемый
Просмотреть файл

@ -13,6 +13,7 @@ extern crate url;
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::{Path, PathBuf};
use url::{Host, HostAndPort, Url, form_urlencoded};
@ -222,7 +223,7 @@ fn test_serialization() {
("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://:@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"),
@ -295,22 +296,6 @@ fn host_and_port_display() {
)
}
#[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.check_invariants().unwrap();
url.set_scheme("postgres").unwrap();
url.check_invariants().unwrap();
url.set_host(Some("")).unwrap();
url.check_invariants().unwrap();
url.set_username("me").unwrap();
url.check_invariants().unwrap();
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() {
@ -382,6 +367,11 @@ fn test_set_host() {
let mut url = Url::parse("foobar://example.net/hello").unwrap();
url.set_host(None).unwrap();
assert_eq!(url.as_str(), "foobar:/hello");
let mut url = Url::parse("foo://ș").unwrap();
assert_eq!(url.as_str(), "foo://%C8%99/");
url.set_host(Some("goșu.ro")).unwrap();
assert_eq!(url.as_str(), "foo://go%C8%99u.ro/");
}
#[test]
@ -488,3 +478,68 @@ fn test_windows_unc_path() {
let url = Url::from_file_path(Path::new(r"\\.\some\path\file.txt"));
assert!(url.is_err());
}
// Test the now deprecated log_syntax_violation method for backward
// compatibility
#[test]
#[allow(deprecated)]
fn test_old_log_violation_option() {
let violation = Cell::new(None);
let url = Url::options()
.log_syntax_violation(Some(&|s| violation.set(Some(s.to_owned()))))
.parse("http:////mozilla.org:42").unwrap();
assert_eq!(url.port(), Some(42));
let violation = violation.take();
assert_eq!(violation, Some("expected //".to_string()));
}
#[test]
fn test_syntax_violation_callback() {
use url::SyntaxViolation::*;
let violation = Cell::new(None);
let url = Url::options()
.syntax_violation_callback(Some(&|v| violation.set(Some(v))))
.parse("http:////mozilla.org:42").unwrap();
assert_eq!(url.port(), Some(42));
let v = violation.take().unwrap();
assert_eq!(v, ExpectedDoubleSlash);
assert_eq!(v.description(), "expected //");
}
#[test]
fn test_syntax_violation_callback_lifetimes() {
use url::SyntaxViolation::*;
let violation = Cell::new(None);
let vfn = |s| violation.set(Some(s));
let url = Url::options()
.syntax_violation_callback(Some(&vfn))
.parse("http:////mozilla.org:42").unwrap();
assert_eq!(url.port(), Some(42));
assert_eq!(violation.take(), Some(ExpectedDoubleSlash));
let url = Url::options()
.syntax_violation_callback(Some(&vfn))
.parse("http://mozilla.org\\path").unwrap();
assert_eq!(url.path(), "/path");
assert_eq!(violation.take(), Some(Backslash));
}
#[test]
fn test_options_reuse() {
use url::SyntaxViolation::*;
let violations = RefCell::new(Vec::new());
let vfn = |v| violations.borrow_mut().push(v);
let options = Url::options()
.syntax_violation_callback(Some(&vfn));
let url = options.parse("http:////mozilla.org").unwrap();
let options = options.base_url(Some(&url));
let url = options.parse("/sub\\path").unwrap();
assert_eq!(url.as_str(), "http://mozilla.org/sub/path");
assert_eq!(*violations.borrow(),
vec!(ExpectedDoubleSlash, Backslash));
}

1791
third_party/rust/url/tests/urltestdata.json поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу