Separate default-tls and native-tls features (#749)
To allow for the default-tls to change to a different backend by default, this adds a new `native-tls` optional feature. Any TLS feature that was only available using native-tls now requires the `native-tls` feature to be enabled.
This commit is contained in:
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -55,6 +55,7 @@ jobs:
|
|||||||
- windows / stable-i686-gnu
|
- windows / stable-i686-gnu
|
||||||
- "feat.: default-tls disabled"
|
- "feat.: default-tls disabled"
|
||||||
- "feat.: rustls-tls"
|
- "feat.: rustls-tls"
|
||||||
|
- "feat.: native-tls"
|
||||||
- "feat.: default-tls and rustls-tls"
|
- "feat.: default-tls and rustls-tls"
|
||||||
- "feat.: cookies"
|
- "feat.: cookies"
|
||||||
- "feat.: blocking"
|
- "feat.: blocking"
|
||||||
@@ -100,6 +101,8 @@ jobs:
|
|||||||
features: "--no-default-features"
|
features: "--no-default-features"
|
||||||
- name: "feat.: rustls-tls"
|
- name: "feat.: rustls-tls"
|
||||||
features: "--no-default-features --features rustls-tls"
|
features: "--no-default-features --features rustls-tls"
|
||||||
|
- name: "feat.: native-tls"
|
||||||
|
features: "--features native-tls"
|
||||||
- name: "feat.: default-tls and rustls-tls"
|
- name: "feat.: default-tls and rustls-tls"
|
||||||
features: "--features rustls-tls"
|
features: "--features rustls-tls"
|
||||||
- name: "feat.: cookies"
|
- name: "feat.: cookies"
|
||||||
|
|||||||
16
Cargo.toml
16
Cargo.toml
@@ -18,12 +18,15 @@ all-features = true
|
|||||||
[features]
|
[features]
|
||||||
default = ["default-tls"]
|
default = ["default-tls"]
|
||||||
|
|
||||||
tls = []
|
# Note: this doesn't enable the 'native-tls' feature, which adds specific
|
||||||
|
# functionality for it.
|
||||||
|
default-tls = ["hyper-tls", "native-tls-crate", "__tls", "tokio-tls"]
|
||||||
|
|
||||||
default-tls = ["hyper-tls", "native-tls", "tls", "tokio-tls"]
|
# Enables native-tls specific functionality not available by default.
|
||||||
default-tls-vendored = ["default-tls", "native-tls/vendored"]
|
native-tls = ["default-tls"]
|
||||||
|
native-tls-vendored = ["native-tls", "native-tls-crate/vendored"]
|
||||||
|
|
||||||
rustls-tls = ["hyper-rustls", "tokio-rustls", "webpki-roots", "rustls", "tls"]
|
rustls-tls = ["hyper-rustls", "tokio-rustls", "webpki-roots", "rustls", "__tls"]
|
||||||
|
|
||||||
blocking = ["futures-channel", "futures-util/io", "tokio/rt-threaded", "tokio/rt-core"]
|
blocking = ["futures-channel", "futures-util/io", "tokio/rt-threaded", "tokio/rt-core"]
|
||||||
|
|
||||||
@@ -40,6 +43,9 @@ stream = []
|
|||||||
# Internal (PRIVATE!) features used to aid testing.
|
# Internal (PRIVATE!) features used to aid testing.
|
||||||
# Don't rely on these whatsoever. They may disappear at anytime.
|
# Don't rely on these whatsoever. They may disappear at anytime.
|
||||||
|
|
||||||
|
# Enables common types used for TLS. Useless on its own.
|
||||||
|
__tls = []
|
||||||
|
|
||||||
# When enabled, disable using the cached SYS_PROXIES.
|
# When enabled, disable using the cached SYS_PROXIES.
|
||||||
__internal_proxy_sys_no_cache = []
|
__internal_proxy_sys_no_cache = []
|
||||||
|
|
||||||
@@ -74,7 +80,7 @@ serde_urlencoded = "0.6.1"
|
|||||||
|
|
||||||
## default-tls
|
## default-tls
|
||||||
hyper-tls = { version = "0.4", optional = true }
|
hyper-tls = { version = "0.4", optional = true }
|
||||||
native-tls = { version = "0.2", optional = true }
|
native-tls-crate = { version = "0.2", optional = true, package = "native-tls" }
|
||||||
tokio-tls = { version = "0.3.0", optional = true }
|
tokio-tls = { version = "0.3.0", optional = true }
|
||||||
|
|
||||||
# rustls-tls
|
# rustls-tls
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ use http::header::{
|
|||||||
use http::Uri;
|
use http::Uri;
|
||||||
use http::uri::Scheme;
|
use http::uri::Scheme;
|
||||||
use hyper::client::ResponseFuture;
|
use hyper::client::ResponseFuture;
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls-crate")]
|
||||||
use native_tls::TlsConnector;
|
use native_tls_crate::TlsConnector;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
@@ -30,9 +30,9 @@ use crate::connect::Connector;
|
|||||||
use crate::cookie;
|
use crate::cookie;
|
||||||
use crate::into_url::{expect_uri, try_uri};
|
use crate::into_url::{expect_uri, try_uri};
|
||||||
use crate::redirect::{self, remove_sensitive_headers};
|
use crate::redirect::{self, remove_sensitive_headers};
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
use crate::tls::TlsBackend;
|
use crate::tls::TlsBackend;
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
use crate::{Certificate, Identity};
|
use crate::{Certificate, Identity};
|
||||||
use crate::{IntoUrl, Method, Proxy, StatusCode, Url};
|
use crate::{IntoUrl, Method, Proxy, StatusCode, Url};
|
||||||
|
|
||||||
@@ -60,22 +60,22 @@ struct Config {
|
|||||||
// NOTE: When adding a new field, update `fmt::Debug for ClientBuilder`
|
// NOTE: When adding a new field, update `fmt::Debug for ClientBuilder`
|
||||||
gzip: bool,
|
gzip: bool,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
hostname_verification: bool,
|
hostname_verification: bool,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
certs_verification: bool,
|
certs_verification: bool,
|
||||||
connect_timeout: Option<Duration>,
|
connect_timeout: Option<Duration>,
|
||||||
max_idle_per_host: usize,
|
max_idle_per_host: usize,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
identity: Option<Identity>,
|
identity: Option<Identity>,
|
||||||
proxies: Vec<Proxy>,
|
proxies: Vec<Proxy>,
|
||||||
auto_sys_proxy: bool,
|
auto_sys_proxy: bool,
|
||||||
redirect_policy: redirect::Policy,
|
redirect_policy: redirect::Policy,
|
||||||
referer: bool,
|
referer: bool,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
root_certs: Vec<Certificate>,
|
root_certs: Vec<Certificate>,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
tls: TlsBackend,
|
tls: TlsBackend,
|
||||||
http2_only: bool,
|
http2_only: bool,
|
||||||
http1_title_case_headers: bool,
|
http1_title_case_headers: bool,
|
||||||
@@ -106,9 +106,9 @@ impl ClientBuilder {
|
|||||||
config: Config {
|
config: Config {
|
||||||
gzip: cfg!(feature = "gzip"),
|
gzip: cfg!(feature = "gzip"),
|
||||||
headers,
|
headers,
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
hostname_verification: true,
|
hostname_verification: true,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
certs_verification: true,
|
certs_verification: true,
|
||||||
connect_timeout: None,
|
connect_timeout: None,
|
||||||
max_idle_per_host: std::usize::MAX,
|
max_idle_per_host: std::usize::MAX,
|
||||||
@@ -117,11 +117,11 @@ impl ClientBuilder {
|
|||||||
redirect_policy: redirect::Policy::default(),
|
redirect_policy: redirect::Policy::default(),
|
||||||
referer: true,
|
referer: true,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
root_certs: Vec::new(),
|
root_certs: Vec::new(),
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
identity: None,
|
identity: None,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
tls: TlsBackend::default(),
|
tls: TlsBackend::default(),
|
||||||
http2_only: false,
|
http2_only: false,
|
||||||
http1_title_case_headers: false,
|
http1_title_case_headers: false,
|
||||||
@@ -150,25 +150,34 @@ impl ClientBuilder {
|
|||||||
let proxies = Arc::new(proxies);
|
let proxies = Arc::new(proxies);
|
||||||
|
|
||||||
let mut connector = {
|
let mut connector = {
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
fn user_agent(headers: &HeaderMap) -> HeaderValue {
|
fn user_agent(headers: &HeaderMap) -> HeaderValue {
|
||||||
headers[USER_AGENT].clone()
|
headers[USER_AGENT].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
match config.tls {
|
match config.tls {
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "default-tls")]
|
||||||
TlsBackend::Default => {
|
TlsBackend::Default => {
|
||||||
let mut tls = TlsConnector::builder();
|
let mut tls = TlsConnector::builder();
|
||||||
tls.danger_accept_invalid_hostnames(!config.hostname_verification);
|
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
|
{
|
||||||
|
tls.danger_accept_invalid_hostnames(!config.hostname_verification);
|
||||||
|
}
|
||||||
|
|
||||||
tls.danger_accept_invalid_certs(!config.certs_verification);
|
tls.danger_accept_invalid_certs(!config.certs_verification);
|
||||||
|
|
||||||
for cert in config.root_certs {
|
for cert in config.root_certs {
|
||||||
cert.add_to_native_tls(&mut tls);
|
cert.add_to_native_tls(&mut tls);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = config.identity {
|
|
||||||
id.add_to_native_tls(&mut tls)?;
|
#[cfg(feature = "native-tls")]
|
||||||
|
{
|
||||||
|
if let Some(id) = config.identity {
|
||||||
|
id.add_to_native_tls(&mut tls)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connector::new_default_tls(
|
Connector::new_default_tls(
|
||||||
@@ -215,7 +224,7 @@ impl ClientBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "__tls"))]
|
||||||
Connector::new(proxies.clone(), config.local_address, config.nodelay)?
|
Connector::new(proxies.clone(), config.local_address, config.nodelay)?
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -511,9 +520,9 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` or `rustls-tls` feature to be
|
/// This requires the optional `default-tls`, `native-tls`, or `rustls-tls`
|
||||||
/// enabled.
|
/// feature to be enabled.
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
pub fn add_root_certificate(mut self, cert: Certificate) -> ClientBuilder {
|
pub fn add_root_certificate(mut self, cert: Certificate) -> ClientBuilder {
|
||||||
self.config.root_certs.push(cert);
|
self.config.root_certs.push(cert);
|
||||||
self
|
self
|
||||||
@@ -523,9 +532,9 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` or `rustls-tls` feature to be
|
/// This requires the optional `native-tls` or `rustls-tls` feature to be
|
||||||
/// enabled.
|
/// enabled.
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
pub fn identity(mut self, identity: Identity) -> ClientBuilder {
|
pub fn identity(mut self, identity: Identity) -> ClientBuilder {
|
||||||
self.config.identity = Some(identity);
|
self.config.identity = Some(identity);
|
||||||
self
|
self
|
||||||
@@ -544,8 +553,8 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` feature to be enabled.
|
/// This requires the optional `native-tls` feature to be enabled.
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
pub fn danger_accept_invalid_hostnames(
|
pub fn danger_accept_invalid_hostnames(
|
||||||
mut self,
|
mut self,
|
||||||
accept_invalid_hostname: bool,
|
accept_invalid_hostname: bool,
|
||||||
@@ -568,9 +577,9 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` or `rustls-tls` feature to be
|
/// This requires the optional `default-tls`, `native-tls`, or `rustls-tls`
|
||||||
/// enabled.
|
/// feature to be enabled.
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
pub fn danger_accept_invalid_certs(mut self, accept_invalid_certs: bool) -> ClientBuilder {
|
pub fn danger_accept_invalid_certs(mut self, accept_invalid_certs: bool) -> ClientBuilder {
|
||||||
self.config.certs_verification = !accept_invalid_certs;
|
self.config.certs_verification = !accept_invalid_certs;
|
||||||
self
|
self
|
||||||
@@ -583,9 +592,9 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` feature to be enabled.
|
/// This requires the optional `native-tls` feature to be enabled.
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
pub fn use_default_tls(mut self) -> ClientBuilder {
|
pub fn use_native_tls(mut self) -> ClientBuilder {
|
||||||
self.config.tls = TlsBackend::Default;
|
self.config.tls = TlsBackend::Default;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -888,21 +897,21 @@ impl Config {
|
|||||||
f.field("tcp_nodelay", &true);
|
f.field("tcp_nodelay", &true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
{
|
{
|
||||||
if !self.hostname_verification {
|
if !self.hostname_verification {
|
||||||
f.field("danger_accept_invalid_hostnames", &true);
|
f.field("danger_accept_invalid_hostnames", &true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
{
|
{
|
||||||
if !self.certs_verification {
|
if !self.certs_verification {
|
||||||
f.field("danger_accept_invalid_certs", &true);
|
f.field("danger_accept_invalid_certs", &true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "default-tls", feature = "rustls-tls"))]
|
#[cfg(all(feature = "native-tls-crate", feature = "rustls-tls"))]
|
||||||
{
|
{
|
||||||
f.field("tls_backend", &self.tls);
|
f.field("tls_backend", &self.tls);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use super::request::{Request, RequestBuilder};
|
|||||||
use super::response::Response;
|
use super::response::Response;
|
||||||
use super::wait;
|
use super::wait;
|
||||||
use crate::{async_impl, header, IntoUrl, Method, Proxy, redirect};
|
use crate::{async_impl, header, IntoUrl, Method, Proxy, redirect};
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
use crate::{Certificate, Identity};
|
use crate::{Certificate, Identity};
|
||||||
|
|
||||||
/// A `Client` to make Requests with.
|
/// A `Client` to make Requests with.
|
||||||
@@ -331,45 +331,15 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` or `rustls-tls` feature to be
|
/// This requires the optional `default-tls`, `native-tls`, or `rustls-tls`
|
||||||
/// enabled.
|
/// feature to be enabled.
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
pub fn add_root_certificate(self, cert: Certificate) -> ClientBuilder {
|
pub fn add_root_certificate(self, cert: Certificate) -> ClientBuilder {
|
||||||
self.with_inner(move |inner| inner.add_root_certificate(cert))
|
self.with_inner(move |inner| inner.add_root_certificate(cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the identity to be used for client certificate authentication.
|
/// Sets the identity to be used for client certificate authentication.
|
||||||
///
|
#[cfg(feature = "__tls")]
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use std::fs::File;
|
|
||||||
/// # use std::io::Read;
|
|
||||||
/// # fn build_client() -> Result<(), Box<std::error::Error>> {
|
|
||||||
/// // read a local PKCS12 bundle
|
|
||||||
/// let mut buf = Vec::new();
|
|
||||||
///
|
|
||||||
/// #[cfg(feature = "default-tls")]
|
|
||||||
/// File::open("my-ident.pfx")?.read_to_end(&mut buf)?;
|
|
||||||
/// #[cfg(feature = "rustls-tls")]
|
|
||||||
/// File::open("my-ident.pem")?.read_to_end(&mut buf)?;
|
|
||||||
///
|
|
||||||
/// #[cfg(feature = "default-tls")]
|
|
||||||
/// // create an Identity from the PKCS#12 archive
|
|
||||||
/// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?;
|
|
||||||
/// #[cfg(feature = "rustls-tls")]
|
|
||||||
/// // create an Identity from the PEM file
|
|
||||||
/// let pkcs12 = reqwest::Identity::from_pem(&buf)?;
|
|
||||||
///
|
|
||||||
/// // get a client builder
|
|
||||||
/// let client = reqwest::blocking::Client::builder()
|
|
||||||
/// .identity(pkcs12)
|
|
||||||
/// .build()?;
|
|
||||||
/// # drop(client);
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
pub fn identity(self, identity: Identity) -> ClientBuilder {
|
pub fn identity(self, identity: Identity) -> ClientBuilder {
|
||||||
self.with_inner(move |inner| inner.identity(identity))
|
self.with_inner(move |inner| inner.identity(identity))
|
||||||
}
|
}
|
||||||
@@ -384,7 +354,11 @@ impl ClientBuilder {
|
|||||||
/// hostname verification is not used, any valid certificate for any
|
/// hostname verification is not used, any valid certificate for any
|
||||||
/// site will be trusted for use from any other. This introduces a
|
/// site will be trusted for use from any other. This introduces a
|
||||||
/// significant vulnerability to man-in-the-middle attacks.
|
/// significant vulnerability to man-in-the-middle attacks.
|
||||||
#[cfg(feature = "default-tls")]
|
///
|
||||||
|
/// # Optional
|
||||||
|
///
|
||||||
|
/// This requires the optional `native-tls` feature to be enabled.
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostname: bool) -> ClientBuilder {
|
pub fn danger_accept_invalid_hostnames(self, accept_invalid_hostname: bool) -> ClientBuilder {
|
||||||
self.with_inner(|inner| inner.danger_accept_invalid_hostnames(accept_invalid_hostname))
|
self.with_inner(|inner| inner.danger_accept_invalid_hostnames(accept_invalid_hostname))
|
||||||
}
|
}
|
||||||
@@ -400,7 +374,7 @@ impl ClientBuilder {
|
|||||||
/// will be trusted for use. This includes expired certificates. This
|
/// will be trusted for use. This includes expired certificates. This
|
||||||
/// introduces significant vulnerabilities, and should only be used
|
/// introduces significant vulnerabilities, and should only be used
|
||||||
/// as a last resort.
|
/// as a last resort.
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
|
pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
|
||||||
self.with_inner(|inner| inner.danger_accept_invalid_certs(accept_invalid_certs))
|
self.with_inner(|inner| inner.danger_accept_invalid_certs(accept_invalid_certs))
|
||||||
}
|
}
|
||||||
@@ -412,10 +386,10 @@ impl ClientBuilder {
|
|||||||
///
|
///
|
||||||
/// # Optional
|
/// # Optional
|
||||||
///
|
///
|
||||||
/// This requires the optional `default-tls` feature to be enabled.
|
/// This requires the optional `native-tls` feature to be enabled.
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
pub fn use_default_tls(self) -> ClientBuilder {
|
pub fn use_native_tls(self) -> ClientBuilder {
|
||||||
self.with_inner(move |inner| inner.use_default_tls())
|
self.with_inner(move |inner| inner.use_native_tls())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Force using the Rustls TLS backend.
|
/// Force using the Rustls TLS backend.
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use http::uri::{Scheme, Authority};
|
|||||||
use http::Uri;
|
use http::Uri;
|
||||||
use hyper::client::connect::{Connected, Connection};
|
use hyper::client::connect::{Connected, Connection};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls-crate")]
|
||||||
use native_tls::{TlsConnector, TlsConnectorBuilder};
|
use native_tls_crate::{TlsConnector, TlsConnectorBuilder};
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
use http::header::HeaderValue;
|
use http::header::HeaderValue;
|
||||||
use bytes::{Buf, BufMut};
|
use bytes::{Buf, BufMut};
|
||||||
|
|
||||||
@@ -38,15 +38,15 @@ pub(crate) struct Connector {
|
|||||||
inner: Inner,
|
inner: Inner,
|
||||||
proxies: Arc<Vec<Proxy>>,
|
proxies: Arc<Vec<Proxy>>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
nodelay: bool,
|
nodelay: bool,
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
user_agent: HeaderValue,
|
user_agent: HeaderValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum Inner {
|
enum Inner {
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "__tls"))]
|
||||||
Http(HttpConnector),
|
Http(HttpConnector),
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "default-tls")]
|
||||||
DefaultTls(HttpConnector, TlsConnector),
|
DefaultTls(HttpConnector, TlsConnector),
|
||||||
@@ -59,7 +59,7 @@ enum Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Connector {
|
impl Connector {
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "__tls"))]
|
||||||
pub(crate) fn new<T>(
|
pub(crate) fn new<T>(
|
||||||
proxies: Arc<Vec<Proxy>>,
|
proxies: Arc<Vec<Proxy>>,
|
||||||
local_addr: T,
|
local_addr: T,
|
||||||
@@ -199,7 +199,7 @@ impl Connector {
|
|||||||
Ok((Box::new(io) as Conn, connected))
|
Ok((Box::new(io) as Conn, connected))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "__tls"))]
|
||||||
Inner::Http(_) => socks::connect(proxy, dst, dns),
|
Inner::Http(_) => socks::connect(proxy, dst, dns),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ impl Connector {
|
|||||||
is_proxy: bool,
|
is_proxy: bool,
|
||||||
) -> Result<Conn, BoxError> {
|
) -> Result<Conn, BoxError> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "__tls"))]
|
||||||
Inner::Http(mut http) => {
|
Inner::Http(mut http) => {
|
||||||
let io = http.call(dst).await?;
|
let io = http.call(dst).await?;
|
||||||
Ok(Conn {
|
Ok(Conn {
|
||||||
@@ -281,7 +281,7 @@ impl Connector {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
let auth = _auth;
|
let auth = _auth;
|
||||||
|
|
||||||
match &self.inner {
|
match &self.inner {
|
||||||
@@ -352,7 +352,7 @@ impl Connector {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "tls"))]
|
#[cfg(not(feature = "__tls"))]
|
||||||
Inner::Http(_) => (),
|
Inner::Http(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,7 +510,7 @@ impl AsyncWrite for Conn {
|
|||||||
pub(crate) type Connecting =
|
pub(crate) type Connecting =
|
||||||
Pin<Box<dyn Future<Output = Result<Conn, BoxError>> + Send>>;
|
Pin<Box<dyn Future<Output = Result<Conn, BoxError>> + Send>>;
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
async fn tunnel<T>(
|
async fn tunnel<T>(
|
||||||
mut conn: T,
|
mut conn: T,
|
||||||
host: String,
|
host: String,
|
||||||
@@ -586,7 +586,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
fn tunnel_eof() -> io::Error {
|
fn tunnel_eof() -> io::Error {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::UnexpectedEof,
|
io::ErrorKind::UnexpectedEof,
|
||||||
@@ -834,7 +834,7 @@ mod socks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::tunnel;
|
use super::tunnel;
|
||||||
|
|||||||
13
src/lib.rs
13
src/lib.rs
@@ -159,9 +159,11 @@
|
|||||||
//! The following are a list of [Cargo features][cargo-features] that can be
|
//! The following are a list of [Cargo features][cargo-features] that can be
|
||||||
//! enabled or disabled:
|
//! enabled or disabled:
|
||||||
//!
|
//!
|
||||||
//! - **default-tls** *(enabled by default)*: Provides TLS support via the
|
//! - **default-tls** *(enabled by default)*: Provides TLS support to connect
|
||||||
//! `native-tls` library to connect over HTTPS.
|
//! over HTTPS.
|
||||||
//! - **default-tls-vendored**: Enables the `vendored` feature of `native-tls`.
|
//! - **native-tls**: Enables TLS functionality provided by `native-tls`.
|
||||||
|
//! - **native-tls-vendored**: Enables the `vendored` feature of `native-tls`.
|
||||||
|
//! - **rustls-tls**: Enables TLS functionality provided by `rustls`.
|
||||||
//! - **blocking**: Provides the [blocking][] client API.
|
//! - **blocking**: Provides the [blocking][] client API.
|
||||||
//! - **cookies**: Provides cookie session support.
|
//! - **cookies**: Provides cookie session support.
|
||||||
//! - **gzip**: Provides response body gzip decompression.
|
//! - **gzip**: Provides response body gzip decompression.
|
||||||
@@ -179,7 +181,6 @@
|
|||||||
//! [Proxy]: ./struct.Proxy.html
|
//! [Proxy]: ./struct.Proxy.html
|
||||||
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section
|
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section
|
||||||
|
|
||||||
////! - **rustls-tls**: Provides TLS support via the `rustls` library.
|
|
||||||
////! - **socks**: Provides SOCKS5 proxy support.
|
////! - **socks**: Provides SOCKS5 proxy support.
|
||||||
////! - **trust-dns**: Enables a trust-dns async resolver instead of default
|
////! - **trust-dns**: Enables a trust-dns async resolver instead of default
|
||||||
////! threadpool using `getaddrinfo`.
|
////! threadpool using `getaddrinfo`.
|
||||||
@@ -278,7 +279,7 @@ if_hyper! {
|
|||||||
multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt,
|
multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt,
|
||||||
};
|
};
|
||||||
pub use self::proxy::Proxy;
|
pub use self::proxy::Proxy;
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
pub use self::tls::{Certificate, Identity};
|
pub use self::tls::{Certificate, Identity};
|
||||||
|
|
||||||
|
|
||||||
@@ -292,7 +293,7 @@ if_hyper! {
|
|||||||
//mod dns;
|
//mod dns;
|
||||||
mod proxy;
|
mod proxy;
|
||||||
pub mod redirect;
|
pub mod redirect;
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
mod tls;
|
mod tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
src/tls.rs
48
src/tls.rs
@@ -4,11 +4,11 @@ use std::fmt;
|
|||||||
#[cfg(feature = "rustls-tls")]
|
#[cfg(feature = "rustls-tls")]
|
||||||
use tokio_rustls::webpki::DNSNameRef;
|
use tokio_rustls::webpki::DNSNameRef;
|
||||||
|
|
||||||
/// Represent a server X509 certificate.
|
/// Represents a server X509 certificate.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Certificate {
|
pub struct Certificate {
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls-crate")]
|
||||||
native: native_tls::Certificate,
|
native: native_tls_crate::Certificate,
|
||||||
#[cfg(feature = "rustls-tls")]
|
#[cfg(feature = "rustls-tls")]
|
||||||
original: Cert,
|
original: Cert,
|
||||||
}
|
}
|
||||||
@@ -20,14 +20,18 @@ enum Cert {
|
|||||||
Pem(Vec<u8>),
|
Pem(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represent a private key and X509 cert as a client certificate.
|
/// Represents a private key and X509 cert as a client certificate.
|
||||||
pub struct Identity {
|
pub struct Identity {
|
||||||
|
#[cfg_attr(
|
||||||
|
not(any(feature = "native-tls", feature = "rustls-tls")),
|
||||||
|
allow(unused)
|
||||||
|
)]
|
||||||
inner: ClientCert,
|
inner: ClientCert,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ClientCert {
|
enum ClientCert {
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
Pkcs12(native_tls::Identity),
|
Pkcs12(native_tls_crate::Identity),
|
||||||
#[cfg(feature = "rustls-tls")]
|
#[cfg(feature = "rustls-tls")]
|
||||||
Pem {
|
Pem {
|
||||||
key: rustls::PrivateKey,
|
key: rustls::PrivateKey,
|
||||||
@@ -54,8 +58,8 @@ impl Certificate {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
|
pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
|
||||||
Ok(Certificate {
|
Ok(Certificate {
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls-crate")]
|
||||||
native: native_tls::Certificate::from_der(der).map_err(crate::error::builder)?,
|
native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
|
||||||
#[cfg(feature = "rustls-tls")]
|
#[cfg(feature = "rustls-tls")]
|
||||||
original: Cert::Der(der.to_owned()),
|
original: Cert::Der(der.to_owned()),
|
||||||
})
|
})
|
||||||
@@ -79,15 +83,15 @@ impl Certificate {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
|
pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
|
||||||
Ok(Certificate {
|
Ok(Certificate {
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls-crate")]
|
||||||
native: native_tls::Certificate::from_pem(pem).map_err(crate::error::builder)?,
|
native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
|
||||||
#[cfg(feature = "rustls-tls")]
|
#[cfg(feature = "rustls-tls")]
|
||||||
original: Cert::Pem(pem.to_owned()),
|
original: Cert::Pem(pem.to_owned()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls-crate")]
|
||||||
pub(crate) fn add_to_native_tls(self, tls: &mut native_tls::TlsConnectorBuilder) {
|
pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
|
||||||
tls.add_root_certificate(self.native);
|
tls.add_root_certificate(self.native);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,11 +151,15 @@ impl Identity {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "default-tls")]
|
///
|
||||||
|
/// # Optional
|
||||||
|
///
|
||||||
|
/// This requires the `native-tls` Cargo feature enabled.
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
|
pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
|
||||||
Ok(Identity {
|
Ok(Identity {
|
||||||
inner: ClientCert::Pkcs12(
|
inner: ClientCert::Pkcs12(
|
||||||
native_tls::Identity::from_pkcs12(der, password).map_err(crate::error::builder)?,
|
native_tls_crate::Identity::from_pkcs12(der, password).map_err(crate::error::builder)?,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -175,6 +183,10 @@ impl Identity {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Optional
|
||||||
|
///
|
||||||
|
/// This requires the `rustls-tls` Cargo feature enabled.
|
||||||
#[cfg(feature = "rustls-tls")]
|
#[cfg(feature = "rustls-tls")]
|
||||||
pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
|
pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
|
||||||
use rustls::internal::pemfile;
|
use rustls::internal::pemfile;
|
||||||
@@ -214,10 +226,10 @@ impl Identity {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
pub(crate) fn add_to_native_tls(
|
pub(crate) fn add_to_native_tls(
|
||||||
self,
|
self,
|
||||||
tls: &mut native_tls::TlsConnectorBuilder,
|
tls: &mut native_tls_crate::TlsConnectorBuilder,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
ClientCert::Pkcs12(id) => {
|
ClientCert::Pkcs12(id) => {
|
||||||
@@ -236,7 +248,7 @@ impl Identity {
|
|||||||
tls.set_single_client_cert(certs, key);
|
tls.set_single_client_cert(certs, key);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
ClientCert::Pkcs12(..) => Err(crate::error::builder("incompatible TLS identity type")),
|
ClientCert::Pkcs12(..) => Err(crate::error::builder("incompatible TLS identity type")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,7 +320,7 @@ mod tests {
|
|||||||
Certificate::from_pem(b"not pem").unwrap_err();
|
Certificate::from_pem(b"not pem").unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
#[test]
|
#[test]
|
||||||
fn identity_from_pkcs12_der_invalid() {
|
fn identity_from_pkcs12_der_invalid() {
|
||||||
Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
|
Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_badssl_modern() {
|
async fn test_badssl_modern() {
|
||||||
let text = reqwest::get("https://mozilla-modern.badssl.com/")
|
let text = reqwest::get("https://mozilla-modern.badssl.com/")
|
||||||
@@ -29,7 +29,7 @@ async fn test_rustls_badssl_modern() {
|
|||||||
assert!(text.contains("<title>mozilla-modern.badssl.com</title>"));
|
assert!(text.contains("<title>mozilla-modern.badssl.com</title>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "__tls")]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_badssl_self_signed() {
|
async fn test_badssl_self_signed() {
|
||||||
let text = reqwest::Client::builder()
|
let text = reqwest::Client::builder()
|
||||||
@@ -47,7 +47,7 @@ async fn test_badssl_self_signed() {
|
|||||||
assert!(text.contains("<title>self-signed.badssl.com</title>"));
|
assert!(text.contains("<title>self-signed.badssl.com</title>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "default-tls")]
|
#[cfg(feature = "native-tls")]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_badssl_wrong_host() {
|
async fn test_badssl_wrong_host() {
|
||||||
let text = reqwest::Client::builder()
|
let text = reqwest::Client::builder()
|
||||||
|
|||||||
Reference in New Issue
Block a user