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:
Sean McArthur
2019-12-20 13:22:56 -08:00
committed by GitHub
parent 18fd9a63b0
commit 24abf2fcbd
8 changed files with 128 additions and 123 deletions

View File

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

View File

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

View File

@@ -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);
} }

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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();

View File

@@ -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()