diff --git a/.travis.yml b/.travis.yml index a5ac7b96a..243d106ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ matrix: script: cargo build --target "$TARGET" --no-default-features # minimum version - - rust: 1.31.0 + - rust: 1.33.0 script: cargo build sudo: false diff --git a/Cargo.toml b/Cargo.toml index 5e7d97d42..e4c3aa7bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,15 +24,16 @@ flate2 = { version = "^1.0.7", default-features = false, features = ["rust_backe log = "0.4" mime = "0.3.7" mime_guess = "2.0.0-alpha.6" +percent-encoding = "2.0" serde = "1.0" serde_json = "1.0" -serde_urlencoded = "0.5" +serde_urlencoded = "0.6" tokio = { version = "0.1.7", default-features = false, features = ["rt-full", "tcp"] } tokio-executor = "0.1.4" # a minimum version so trust-dns-resolver compiles tokio-io = "0.1" tokio-threadpool = "0.1.8" # a minimum version so tokio compiles tokio-timer = "0.2.6" # a minimum version so trust-dns-resolver compiles -url = "1.2" +url = "2.0" uuid = { version = "0.7", features = ["v4"] } # Optional deps... @@ -46,7 +47,7 @@ socks = { version = "0.3.2", optional = true } tokio-rustls = { version = "0.9", optional = true } trust-dns-resolver = { version = "0.11", optional = true } webpki-roots = { version = "0.16", optional = true } -cookie_store = "0.7.0" +cookie_store = "0.8.0" cookie = "0.12.0" time = "0.1.42" @@ -75,3 +76,9 @@ hyper-011 = ["hyper-old-types"] [target.'cfg(windows)'.dependencies] winreg = "0.6" + +[patch.crates-io] +cookie = { git = "https://github.com/benesch/cookie-rs", branch = "url-20" } +publicsuffix = { git = "https://github.com/benesch/publicsuffix" } +cookie_store = { git = "https://github.com/benesch/cookie_store", branch = "url-20" } +serde_urlencoded = { git = "https://github.com/benesch/serde_urlencoded", branch = "url-20" } \ No newline at end of file diff --git a/src/async_impl/multipart.rs b/src/async_impl/multipart.rs index fec4428fd..e1208a8c5 100644 --- a/src/async_impl/multipart.rs +++ b/src/async_impl/multipart.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use std::fmt; use mime_guess::Mime; -use url::percent_encoding::{self, EncodeSet, PATH_SEGMENT_ENCODE_SET}; +use percent_encoding::{self, AsciiSet}; use uuid::Uuid; use http::HeaderMap; @@ -371,31 +371,39 @@ impl PartMetadata { } } -#[derive(Debug, Clone)] -pub(crate) struct AttrCharEncodeSet; - -impl EncodeSet for AttrCharEncodeSet { - fn contains(&self, ch: u8) -> bool { - match ch as char { - '!' => false, - '#' => false, - '$' => false, - '&' => false, - '+' => false, - '-' => false, - '.' => false, - '^' => false, - '_' => false, - '`' => false, - '|' => false, - '~' => false, - _ => { - let is_alpha_numeric = ch >= 0x41 && ch <= 0x5a || ch >= 0x61 && ch <= 0x7a || ch >= 0x30 && ch <= 0x39; - !is_alpha_numeric - } - } - } -} +/// https://url.spec.whatwg.org/#fragment-percent-encode-set +const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`'); + +/// https://url.spec.whatwg.org/#path-percent-encode-set +const PATH_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'#').add(b'?').add(b'{').add(b'}'); + +const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &PATH_ENCODE_SET.add(b'/').add(b'%'); + +// This will be a bit shorter to express when AsciiSet.remove lands: +// https://github.com/servo/rust-url/pull/528. +/// https://tools.ietf.org/html/rfc8187#section-3.2.1 +const ATTR_CHAR_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS + .add(b' ') + .add(b'"') + .add(b'%') + .add(b'\'') + .add(b'(') + .add(b')') + .add(b'*') + .add(b',') + .add(b'/') + .add(b':') + .add(b';') + .add(b'<') + .add(b'=') + .add(b'>') + .add(b'?') + .add(b'@') + .add(b'[') + .add(b'\\') + .add(b']') + .add(b'{') + .add(b'}'); pub(crate) enum PercentEncoding { PathSegment, @@ -443,7 +451,7 @@ impl PercentEncoding { .to_string() }, PercentEncoding::AttrChar => { - percent_encoding::utf8_percent_encode(value, AttrCharEncodeSet) + percent_encoding::utf8_percent_encode(value, ATTR_CHAR_ENCODE_SET) .to_string() }, PercentEncoding::NoOp => { value.to_string() }, diff --git a/src/lib.rs b/src/lib.rs index 6e1b73da0..396584eda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -193,6 +193,7 @@ extern crate mime; extern crate mime_guess; #[cfg(feature = "default-tls")] extern crate native_tls; +extern crate percent_encoding; extern crate serde; extern crate serde_json; extern crate serde_urlencoded; diff --git a/src/proxy.rs b/src/proxy.rs index 257632505..9fb863bd6 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -5,10 +5,12 @@ use std::net::{SocketAddr, ToSocketAddrs}; use http::{header::HeaderValue, Uri}; use hyper::client::connect::Destination; -use url::percent_encoding::percent_decode; +use percent_encoding::percent_decode; use {IntoUrl, Url}; use std::collections::HashMap; use std::env; +#[cfg(feature = "socks")] +use std::io; #[cfg(target_os = "windows")] use std::error::Error; #[cfg(target_os = "windows")] @@ -330,11 +332,15 @@ impl ProxyScheme { // Resolve URL to a host and port #[cfg(feature = "socks")] let to_addr = || { - let host_and_port = try_!(url.with_default_port(|url| match url.scheme() { - "socks5" | "socks5h" => Ok(1080), - _ => Err(()) - })); - let mut addr = try_!(host_and_port.to_socket_addrs()); + let host = try_!(url.host_str().ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "URL has no host"))); + let port = try_!(match url.port_or_known_default() { + Some(port) => Ok(port), + None => match url.scheme() { + "socks5" | "socks5h" => Ok(1080), + _ => Err(io::Error::new(io::ErrorKind::InvalidData, "URL has no port")), + } + }); + let mut addr = try_!(format!("{}:{}", host, port).to_socket_addrs()); addr .next() .ok_or_else(::error::unknown_proxy_scheme)