put all TLS functionality behind a feature flag
The "Cargo feature" `default-tls`, which is enabled by default, is added, with all TLS support relying on it. This allows using reqwest but disabling the `native-tls` dependency, by disabling this feature. Closes #225
This commit is contained in:
		
							
								
								
									
										11
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -8,18 +8,15 @@ matrix: | |||||||
|           rust: stable |           rust: stable | ||||||
|  |  | ||||||
|         - rust: stable |         - rust: stable | ||||||
|           env: FEATURES="" |  | ||||||
|         - rust: beta |         - rust: beta | ||||||
|           env: FEATURES="" |  | ||||||
|         - rust: nightly |         - rust: nightly | ||||||
|           env: FEATURES="" |  | ||||||
|  |         # Disable default-tls | ||||||
|  |         - rust: stable | ||||||
|  |           env: FEATURES="--no-default-features" | ||||||
|  |  | ||||||
|         - rust: stable |         - rust: stable | ||||||
|           env: FEATURES="--features hyper-011" |           env: FEATURES="--features hyper-011" | ||||||
|         - rust: beta |  | ||||||
|           env: FEATURES="--features hyper-011" |  | ||||||
|         - rust: nightly |  | ||||||
|           env: FEATURES="--features hyper-011" |  | ||||||
|  |  | ||||||
|         # minimum version |         # minimum version | ||||||
|         - rust: 1.26.0 |         - rust: 1.26.0 | ||||||
|   | |||||||
| @@ -17,12 +17,12 @@ futures = "0.1.23" | |||||||
| http = "0.1.10" | http = "0.1.10" | ||||||
| hyper = "0.12.13" | hyper = "0.12.13" | ||||||
| hyper-old-types = { version = "0.11", optional = true, features = ["compat"] } | hyper-old-types = { version = "0.11", optional = true, features = ["compat"] } | ||||||
| hyper-tls = "0.3" | hyper-tls = { version = "0.3", optional = true } | ||||||
| libflate = "0.1.18" | libflate = "0.1.18" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| mime = "0.3.7" | mime = "0.3.7" | ||||||
| mime_guess = "2.0.0-alpha.6" | mime_guess = "2.0.0-alpha.6" | ||||||
| native-tls = "0.2" | native-tls = { version = "0.2", optional = true } | ||||||
| serde = "1.0" | serde = "1.0" | ||||||
| serde_json = "1.0" | serde_json = "1.0" | ||||||
| serde_urlencoded = "0.5" | serde_urlencoded = "0.5" | ||||||
| @@ -36,8 +36,9 @@ env_logger = "0.5" | |||||||
| serde_derive = "1.0" | serde_derive = "1.0" | ||||||
|  |  | ||||||
| [features] | [features] | ||||||
| default = [] | default = ["default-tls"] | ||||||
| hyper-011 = ["hyper-old-types"] | hyper-011 = ["hyper-old-types"] | ||||||
|  | default-tls = ["hyper-tls", "native-tls"] | ||||||
|  |  | ||||||
| [package.metadata.docs.rs] | [package.metadata.docs.rs] | ||||||
| rustdoc-args = ["--cfg", "docs_rs_workaround"] | rustdoc-args = ["--cfg", "docs_rs_workaround"] | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ use hyper::client::ResponseFuture; | |||||||
| use header::{HeaderMap, HeaderValue, LOCATION, USER_AGENT, REFERER, ACCEPT, | use header::{HeaderMap, HeaderValue, LOCATION, USER_AGENT, REFERER, ACCEPT, | ||||||
|              ACCEPT_ENCODING, RANGE, TRANSFER_ENCODING, CONTENT_TYPE, CONTENT_LENGTH, CONTENT_ENCODING}; |              ACCEPT_ENCODING, RANGE, TRANSFER_ENCODING, CONTENT_TYPE, CONTENT_LENGTH, CONTENT_ENCODING}; | ||||||
| use mime::{self}; | use mime::{self}; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| use native_tls::{TlsConnector, TlsConnectorBuilder}; | use native_tls::{TlsConnector, TlsConnectorBuilder}; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -16,7 +17,9 @@ use super::response::Response; | |||||||
| use connect::Connector; | use connect::Connector; | ||||||
| use into_url::to_uri; | use into_url::to_uri; | ||||||
| use redirect::{self, RedirectPolicy, remove_sensitive_headers}; | use redirect::{self, RedirectPolicy, remove_sensitive_headers}; | ||||||
| use {Certificate, Identity, IntoUrl, Method, Proxy, StatusCode, Url}; | use {IntoUrl, Method, Proxy, StatusCode, Url}; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
|  | use {Certificate, Identity}; | ||||||
|  |  | ||||||
| static DEFAULT_USER_AGENT: &'static str = | static DEFAULT_USER_AGENT: &'static str = | ||||||
|     concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); |     concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); | ||||||
| @@ -41,12 +44,15 @@ pub struct ClientBuilder { | |||||||
| struct Config { | struct Config { | ||||||
|     gzip: bool, |     gzip: bool, | ||||||
|     headers: HeaderMap, |     headers: HeaderMap, | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     hostname_verification: bool, |     hostname_verification: bool, | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     certs_verification: bool, |     certs_verification: bool, | ||||||
|     proxies: Vec<Proxy>, |     proxies: Vec<Proxy>, | ||||||
|     redirect_policy: RedirectPolicy, |     redirect_policy: RedirectPolicy, | ||||||
|     referer: bool, |     referer: bool, | ||||||
|     timeout: Option<Duration>, |     timeout: Option<Duration>, | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     tls: TlsConnectorBuilder, |     tls: TlsConnectorBuilder, | ||||||
|     dns_threads: usize, |     dns_threads: usize, | ||||||
| } | } | ||||||
| @@ -62,12 +68,15 @@ impl ClientBuilder { | |||||||
|             config: Config { |             config: Config { | ||||||
|                 gzip: true, |                 gzip: true, | ||||||
|                 headers: headers, |                 headers: headers, | ||||||
|  |                 #[cfg(feature = "default-tls")] | ||||||
|                 hostname_verification: true, |                 hostname_verification: true, | ||||||
|  |                 #[cfg(feature = "default-tls")] | ||||||
|                 certs_verification: true, |                 certs_verification: true, | ||||||
|                 proxies: Vec::new(), |                 proxies: Vec::new(), | ||||||
|                 redirect_policy: RedirectPolicy::default(), |                 redirect_policy: RedirectPolicy::default(), | ||||||
|                 referer: true, |                 referer: true, | ||||||
|                 timeout: None, |                 timeout: None, | ||||||
|  |                 #[cfg(feature = "default-tls")] | ||||||
|                 tls: TlsConnector::builder(), |                 tls: TlsConnector::builder(), | ||||||
|                 dns_threads: 4, |                 dns_threads: 4, | ||||||
|             }, |             }, | ||||||
| @@ -80,16 +89,31 @@ impl ClientBuilder { | |||||||
|     /// |     /// | ||||||
|     /// This method fails if native TLS backend cannot be initialized. |     /// This method fails if native TLS backend cannot be initialized. | ||||||
|     pub fn build(self) -> ::Result<Client> { |     pub fn build(self) -> ::Result<Client> { | ||||||
|         let mut config = self.config; |         let config = self.config; | ||||||
|  |  | ||||||
|         config.tls.danger_accept_invalid_hostnames(!config.hostname_verification); |  | ||||||
|         config.tls.danger_accept_invalid_certs(!config.certs_verification); |  | ||||||
|  |  | ||||||
|         let tls = try_!(config.tls.build()); |         let connector = { | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|  |             { | ||||||
|  |             let mut tls = config.tls; | ||||||
|  |             tls.danger_accept_invalid_hostnames(!config.hostname_verification); | ||||||
|  |             tls.danger_accept_invalid_certs(!config.certs_verification); | ||||||
|  |  | ||||||
|  |             let tls = try_!(tls.build()); | ||||||
|  |  | ||||||
|             let proxies = Arc::new(config.proxies); |             let proxies = Arc::new(config.proxies); | ||||||
|  |  | ||||||
|         let connector = Connector::new(config.dns_threads, tls, proxies.clone()); |             Connector::new(config.dns_threads, tls, proxies.clone()) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             #[cfg(not(feature = "default-tls"))] | ||||||
|  |             { | ||||||
|  |             let proxies = Arc::new(config.proxies); | ||||||
|  |  | ||||||
|  |             Connector::new(config.dns_threads, proxies.clone()) | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|         let hyper_client = ::hyper::Client::builder() |         let hyper_client = ::hyper::Client::builder() | ||||||
|             .build(connector); |             .build(connector); | ||||||
| @@ -109,12 +133,14 @@ impl ClientBuilder { | |||||||
|     /// |     /// | ||||||
|     /// This can be used to connect to a server that has a self-signed |     /// This can be used to connect to a server that has a self-signed | ||||||
|     /// certificate for example. |     /// certificate for example. | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     pub fn add_root_certificate(mut self, cert: Certificate) -> ClientBuilder { |     pub fn add_root_certificate(mut self, cert: Certificate) -> ClientBuilder { | ||||||
|         self.config.tls.add_root_certificate(cert.cert()); |         self.config.tls.add_root_certificate(cert.cert()); | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Sets the identity to be used for client certificate authentication. |     /// Sets the identity to be used for client certificate authentication. | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     pub fn identity(mut self, identity: Identity) -> ClientBuilder { |     pub fn identity(mut self, identity: Identity) -> ClientBuilder { | ||||||
|         self.config.tls.identity(identity.pkcs12()); |         self.config.tls.identity(identity.pkcs12()); | ||||||
|         self |         self | ||||||
| @@ -130,6 +156,7 @@ 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")] | ||||||
|     pub fn danger_accept_invalid_hostnames(mut self, accept_invalid_hostname: bool) -> ClientBuilder { |     pub fn danger_accept_invalid_hostnames(mut self, accept_invalid_hostname: bool) -> ClientBuilder { | ||||||
|         self.config.hostname_verification = !accept_invalid_hostname; |         self.config.hostname_verification = !accept_invalid_hostname; | ||||||
|         self |         self | ||||||
| @@ -147,6 +174,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 = "default-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 | ||||||
|   | |||||||
| @@ -9,7 +9,9 @@ use futures::sync::{mpsc, oneshot}; | |||||||
|  |  | ||||||
| use request::{Request, RequestBuilder}; | use request::{Request, RequestBuilder}; | ||||||
| use response::Response; | use response::Response; | ||||||
| use {async_impl, header, Certificate, Identity, Method, IntoUrl, Proxy, RedirectPolicy, wait}; | use {async_impl, header, Method, IntoUrl, Proxy, RedirectPolicy, wait}; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
|  | use {Certificate, Identity}; | ||||||
|  |  | ||||||
| /// A `Client` to make Requests with. | /// A `Client` to make Requests with. | ||||||
| /// | /// | ||||||
| @@ -106,6 +108,7 @@ impl ClientBuilder { | |||||||
|     /// # Errors |     /// # Errors | ||||||
|     /// |     /// | ||||||
|     /// This method fails if adding root certificate was unsuccessful. |     /// This method fails if adding root certificate was unsuccessful. | ||||||
|  |     #[cfg(feature = "default-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)) | ||||||
|     } |     } | ||||||
| @@ -133,6 +136,7 @@ impl ClientBuilder { | |||||||
|     /// # Ok(()) |     /// # Ok(()) | ||||||
|     /// # } |     /// # } | ||||||
|     /// ``` |     /// ``` | ||||||
|  |     #[cfg(feature = "default-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)) | ||||||
|     } |     } | ||||||
| @@ -148,6 +152,7 @@ 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")] | ||||||
|     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)) | ||||||
|     } |     } | ||||||
| @@ -164,6 +169,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 = "default-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)) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,34 +1,50 @@ | |||||||
| use bytes::{Buf, BufMut, IntoBuf}; | use bytes::{Buf, BufMut}; | ||||||
| use futures::{Async, Future, Poll}; | use futures::{Future, Poll}; | ||||||
| use http::uri::Scheme; | use http::uri::Scheme; | ||||||
| use hyper::client::{HttpConnector}; | use hyper::client::{HttpConnector}; | ||||||
| use hyper::client::connect::{Connect, Connected, Destination}; | use hyper::client::connect::{Connect, Connected, Destination}; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| use hyper_tls::{HttpsConnector, MaybeHttpsStream}; | use hyper_tls::{HttpsConnector, MaybeHttpsStream}; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| use native_tls::TlsConnector; | use native_tls::TlsConnector; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| use connect_async::{TlsConnectorExt, TlsStream}; | use connect_async::{TlsConnectorExt, TlsStream}; | ||||||
|  |  | ||||||
| use std::io::{self, Cursor, Read, Write}; | use std::io::{self, Read, Write}; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
|  |  | ||||||
| use Proxy; | use Proxy; | ||||||
|  |  | ||||||
| pub(crate) struct Connector { | pub(crate) struct Connector { | ||||||
|     https: HttpsConnector<HttpConnector>, |     #[cfg(feature = "default-tls")] | ||||||
|  |     http: HttpsConnector<HttpConnector>, | ||||||
|  |     #[cfg(not(feature = "default-tls"))] | ||||||
|  |     http: HttpConnector, | ||||||
|     proxies: Arc<Vec<Proxy>>, |     proxies: Arc<Vec<Proxy>>, | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     tls: TlsConnector, |     tls: TlsConnector, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Connector { | impl Connector { | ||||||
|  |     #[cfg(not(feature = "default-tls"))] | ||||||
|  |     pub(crate) fn new(threads: usize, proxies: Arc<Vec<Proxy>>) -> Connector { | ||||||
|  |         let http = HttpConnector::new(threads); | ||||||
|  |         Connector { | ||||||
|  |             http, | ||||||
|  |             proxies, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     pub(crate) fn new(threads: usize, tls: TlsConnector, proxies: Arc<Vec<Proxy>>) -> Connector { |     pub(crate) fn new(threads: usize, tls: TlsConnector, proxies: Arc<Vec<Proxy>>) -> Connector { | ||||||
|         let mut http = HttpConnector::new(threads); |         let mut http = HttpConnector::new(threads); | ||||||
|         http.enforce_http(false); |         http.enforce_http(false); | ||||||
|         let https = HttpsConnector::from((http, tls.clone())); |         let http = HttpsConnector::from((http, tls.clone())); | ||||||
|  |  | ||||||
|         Connector { |         Connector { | ||||||
|             https: https, |             http, | ||||||
|             proxies: proxies, |             proxies, | ||||||
|             tls: tls, |             tls, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -55,11 +71,13 @@ impl Connect for Connector { | |||||||
|  |  | ||||||
|                 ndst.set_port(puri.port()); |                 ndst.set_port(puri.port()); | ||||||
|  |  | ||||||
|  |                 #[cfg(feature = "default-tls")] | ||||||
|  |                 { | ||||||
|                 if dst.scheme() == "https" { |                 if dst.scheme() == "https" { | ||||||
|                     let host = dst.host().to_owned(); |                     let host = dst.host().to_owned(); | ||||||
|                     let port = dst.port().unwrap_or(443); |                     let port = dst.port().unwrap_or(443); | ||||||
|                     let tls = self.tls.clone(); |                     let tls = self.tls.clone(); | ||||||
|                     return Box::new(self.https.connect(ndst).and_then(move |(conn, connected)| { |                     return Box::new(self.http.connect(ndst).and_then(move |(conn, connected)| { | ||||||
|                         trace!("tunneling HTTPS over proxy"); |                         trace!("tunneling HTTPS over proxy"); | ||||||
|                         tunnel(conn, host.clone(), port) |                         tunnel(conn, host.clone(), port) | ||||||
|                             .and_then(move |tunneled| { |                             .and_then(move |tunneled| { | ||||||
| @@ -69,20 +87,27 @@ impl Connect for Connector { | |||||||
|                             .map(|io| (Conn::Proxied(io), connected.proxy(true))) |                             .map(|io| (Conn::Proxied(io), connected.proxy(true))) | ||||||
|                     })); |                     })); | ||||||
|                 } |                 } | ||||||
|                 return Box::new(self.https.connect(ndst).map(|(io, connected)| (Conn::Normal(io), connected.proxy(true)))); |                 } | ||||||
|  |                 return Box::new(self.http.connect(ndst).map(|(io, connected)| (Conn::Normal(io), connected.proxy(true)))); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         Box::new(self.https.connect(dst).map(|(io, connected)| (Conn::Normal(io), connected))) |         Box::new(self.http.connect(dst).map(|(io, connected)| (Conn::Normal(io), connected))) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| type HttpStream = <HttpConnector as Connect>::Transport; | type HttpStream = <HttpConnector as Connect>::Transport; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| type HttpsStream = MaybeHttpsStream<HttpStream>; | type HttpsStream = MaybeHttpsStream<HttpStream>; | ||||||
|  |  | ||||||
|  |  | ||||||
| pub(crate) type Connecting = Box<Future<Item=(Conn, Connected), Error=io::Error> + Send>; | pub(crate) type Connecting = Box<Future<Item=(Conn, Connected), Error=io::Error> + Send>; | ||||||
|  |  | ||||||
| pub(crate) enum Conn { | pub(crate) enum Conn { | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     Normal(HttpsStream), |     Normal(HttpsStream), | ||||||
|  |     #[cfg(not(feature = "default-tls"))] | ||||||
|  |     Normal(HttpStream), | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     Proxied(TlsStream<MaybeHttpsStream<HttpStream>>), |     Proxied(TlsStream<MaybeHttpsStream<HttpStream>>), | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -91,6 +116,7 @@ impl Read for Conn { | |||||||
|     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref mut s) => s.read(buf), |             Conn::Normal(ref mut s) => s.read(buf), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref mut s) => s.read(buf), |             Conn::Proxied(ref mut s) => s.read(buf), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -101,6 +127,7 @@ impl Write for Conn { | |||||||
|     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref mut s) => s.write(buf), |             Conn::Normal(ref mut s) => s.write(buf), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref mut s) => s.write(buf), |             Conn::Proxied(ref mut s) => s.write(buf), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -109,6 +136,7 @@ impl Write for Conn { | |||||||
|     fn flush(&mut self) -> io::Result<()> { |     fn flush(&mut self) -> io::Result<()> { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref mut s) => s.flush(), |             Conn::Normal(ref mut s) => s.flush(), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref mut s) => s.flush(), |             Conn::Proxied(ref mut s) => s.flush(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -118,6 +146,7 @@ impl AsyncRead for Conn { | |||||||
|     unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { |     unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref s) => s.prepare_uninitialized_buffer(buf), |             Conn::Normal(ref s) => s.prepare_uninitialized_buffer(buf), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref s) => s.prepare_uninitialized_buffer(buf), |             Conn::Proxied(ref s) => s.prepare_uninitialized_buffer(buf), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -125,6 +154,7 @@ impl AsyncRead for Conn { | |||||||
|     fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { |     fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref mut s) => s.read_buf(buf), |             Conn::Normal(ref mut s) => s.read_buf(buf), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref mut s) => s.read_buf(buf), |             Conn::Proxied(ref mut s) => s.read_buf(buf), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -134,6 +164,7 @@ impl AsyncWrite for Conn { | |||||||
|     fn shutdown(&mut self) -> Poll<(), io::Error> { |     fn shutdown(&mut self) -> Poll<(), io::Error> { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref mut s) => s.shutdown(), |             Conn::Normal(ref mut s) => s.shutdown(), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref mut s) => s.shutdown(), |             Conn::Proxied(ref mut s) => s.shutdown(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -141,11 +172,13 @@ impl AsyncWrite for Conn { | |||||||
|     fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { |     fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> { | ||||||
|         match *self { |         match *self { | ||||||
|             Conn::Normal(ref mut s) => s.write_buf(buf), |             Conn::Normal(ref mut s) => s.write_buf(buf), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Conn::Proxied(ref mut s) => s.write_buf(buf), |             Conn::Proxied(ref mut s) => s.write_buf(buf), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| fn tunnel<T>(conn: T, host: String, port: u16) -> Tunnel<T> { | fn tunnel<T>(conn: T, host: String, port: u16) -> Tunnel<T> { | ||||||
|      let buf = format!("\ |      let buf = format!("\ | ||||||
|         CONNECT {0}:{1} HTTP/1.1\r\n\ |         CONNECT {0}:{1} HTTP/1.1\r\n\ | ||||||
| @@ -154,23 +187,26 @@ fn tunnel<T>(conn: T, host: String, port: u16) -> Tunnel<T> { | |||||||
|     ", host, port).into_bytes(); |     ", host, port).into_bytes(); | ||||||
|  |  | ||||||
|      Tunnel { |      Tunnel { | ||||||
|         buf: buf.into_buf(), |         buf: io::Cursor::new(buf), | ||||||
|         conn: Some(conn), |         conn: Some(conn), | ||||||
|         state: TunnelState::Writing, |         state: TunnelState::Writing, | ||||||
|      } |      } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| struct Tunnel<T> { | struct Tunnel<T> { | ||||||
|     buf: Cursor<Vec<u8>>, |     buf: io::Cursor<Vec<u8>>, | ||||||
|     conn: Option<T>, |     conn: Option<T>, | ||||||
|     state: TunnelState, |     state: TunnelState, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| enum TunnelState { | enum TunnelState { | ||||||
|     Writing, |     Writing, | ||||||
|     Reading |     Reading | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| impl<T> Future for Tunnel<T> | impl<T> Future for Tunnel<T> | ||||||
| where T: AsyncRead + AsyncWrite { | where T: AsyncRead + AsyncWrite { | ||||||
|     type Item = T; |     type Item = T; | ||||||
| @@ -194,7 +230,7 @@ where T: AsyncRead + AsyncWrite { | |||||||
|                 } else if read.len() > 12 { |                 } else if read.len() > 12 { | ||||||
|                     if read.starts_with(b"HTTP/1.1 200") || read.starts_with(b"HTTP/1.0 200") { |                     if read.starts_with(b"HTTP/1.1 200") || read.starts_with(b"HTTP/1.0 200") { | ||||||
|                         if read.ends_with(b"\r\n\r\n") { |                         if read.ends_with(b"\r\n\r\n") { | ||||||
|                             return Ok(Async::Ready(self.conn.take().unwrap())); |                             return Ok(self.conn.take().unwrap().into()); | ||||||
|                         } |                         } | ||||||
|                         // else read more |                         // else read more | ||||||
|                     } else { |                     } else { | ||||||
| @@ -206,6 +242,7 @@ where T: AsyncRead + AsyncWrite { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| #[inline] | #[inline] | ||||||
| fn tunnel_eof() -> io::Error { | fn tunnel_eof() -> io::Error { | ||||||
|     io::Error::new( |     io::Error::new( | ||||||
| @@ -214,6 +251,7 @@ fn tunnel_eof() -> io::Error { | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use std::io::{Read, Write}; |     use std::io::{Read, Write}; | ||||||
|   | |||||||
| @@ -1,8 +1,7 @@ | |||||||
| use std::io::{self, Read, Write}; | use std::io::{self, Read, Write}; | ||||||
|  |  | ||||||
| use futures::{Poll, Future, Async}; | use futures::{Poll, Future, Async}; | ||||||
| use native_tls; | use native_tls::{self, HandshakeError, Error, TlsConnector}; | ||||||
| use native_tls::{HandshakeError, Error, TlsConnector}; |  | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  |  | ||||||
| /// A wrapper around an underlying raw stream which implements the TLS or SSL | /// A wrapper around an underlying raw stream which implements the TLS or SSL | ||||||
|   | |||||||
| @@ -135,6 +135,7 @@ impl Error { | |||||||
|             Kind::Hyper(ref e) => Some(e), |             Kind::Hyper(ref e) => Some(e), | ||||||
|             Kind::Mime(ref e) => Some(e), |             Kind::Mime(ref e) => Some(e), | ||||||
|             Kind::Url(ref e) => Some(e), |             Kind::Url(ref e) => Some(e), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Kind::Tls(ref e) => Some(e), |             Kind::Tls(ref e) => Some(e), | ||||||
|             Kind::Io(ref e) => Some(e), |             Kind::Io(ref e) => Some(e), | ||||||
|             Kind::UrlEncoded(ref e) => Some(e), |             Kind::UrlEncoded(ref e) => Some(e), | ||||||
| @@ -224,6 +225,7 @@ impl fmt::Display for Error { | |||||||
|             Kind::Mime(ref e) => fmt::Display::fmt(e, f), |             Kind::Mime(ref e) => fmt::Display::fmt(e, f), | ||||||
|             Kind::Url(ref e) => fmt::Display::fmt(e, f), |             Kind::Url(ref e) => fmt::Display::fmt(e, f), | ||||||
|             Kind::UrlBadScheme => f.write_str("URL scheme is not allowed"), |             Kind::UrlBadScheme => f.write_str("URL scheme is not allowed"), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Kind::Tls(ref e) => fmt::Display::fmt(e, f), |             Kind::Tls(ref e) => fmt::Display::fmt(e, f), | ||||||
|             Kind::Io(ref e) => fmt::Display::fmt(e, f), |             Kind::Io(ref e) => fmt::Display::fmt(e, f), | ||||||
|             Kind::UrlEncoded(ref e) => fmt::Display::fmt(e, f), |             Kind::UrlEncoded(ref e) => fmt::Display::fmt(e, f), | ||||||
| @@ -250,6 +252,7 @@ impl StdError for Error { | |||||||
|             Kind::Mime(ref e) => e.description(), |             Kind::Mime(ref e) => e.description(), | ||||||
|             Kind::Url(ref e) => e.description(), |             Kind::Url(ref e) => e.description(), | ||||||
|             Kind::UrlBadScheme => "URL scheme is not allowed", |             Kind::UrlBadScheme => "URL scheme is not allowed", | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Kind::Tls(ref e) => e.description(), |             Kind::Tls(ref e) => e.description(), | ||||||
|             Kind::Io(ref e) => e.description(), |             Kind::Io(ref e) => e.description(), | ||||||
|             Kind::UrlEncoded(ref e) => e.description(), |             Kind::UrlEncoded(ref e) => e.description(), | ||||||
| @@ -267,6 +270,7 @@ impl StdError for Error { | |||||||
|             Kind::Hyper(ref e) => e.cause(), |             Kind::Hyper(ref e) => e.cause(), | ||||||
|             Kind::Mime(ref e) => e.cause(), |             Kind::Mime(ref e) => e.cause(), | ||||||
|             Kind::Url(ref e) => e.cause(), |             Kind::Url(ref e) => e.cause(), | ||||||
|  |             #[cfg(feature = "default-tls")] | ||||||
|             Kind::Tls(ref e) => e.cause(), |             Kind::Tls(ref e) => e.cause(), | ||||||
|             Kind::Io(ref e) => e.cause(), |             Kind::Io(ref e) => e.cause(), | ||||||
|             Kind::UrlEncoded(ref e) => e.cause(), |             Kind::UrlEncoded(ref e) => e.cause(), | ||||||
| @@ -287,6 +291,7 @@ pub(crate) enum Kind { | |||||||
|     Mime(::mime::FromStrError), |     Mime(::mime::FromStrError), | ||||||
|     Url(::url::ParseError), |     Url(::url::ParseError), | ||||||
|     UrlBadScheme, |     UrlBadScheme, | ||||||
|  |     #[cfg(feature = "default-tls")] | ||||||
|     Tls(::native_tls::Error), |     Tls(::native_tls::Error), | ||||||
|     Io(io::Error), |     Io(io::Error), | ||||||
|     UrlEncoded(::serde_urlencoded::ser::Error), |     UrlEncoded(::serde_urlencoded::ser::Error), | ||||||
| @@ -347,6 +352,7 @@ impl From<::serde_json::Error> for Kind { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| impl From<::native_tls::Error> for Kind { | impl From<::native_tls::Error> for Kind { | ||||||
|     fn from(err: ::native_tls::Error) -> Kind { |     fn from(err: ::native_tls::Error) -> Kind { | ||||||
|         Kind::Tls(err) |         Kind::Tls(err) | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -117,6 +117,16 @@ | |||||||
| //! # } | //! # } | ||||||
| //! ``` | //! ``` | ||||||
| //! | //! | ||||||
|  | //! ## Optional Features | ||||||
|  | //! | ||||||
|  | //! The following are a list of [Cargo features][cargo-features] that can be | ||||||
|  | //! enabled or disabled: | ||||||
|  | //! | ||||||
|  | //! - **default-tls** *(enabled by default)*: Provides TLS support via the | ||||||
|  | //!   `native-tls` library to connect over HTTPS. | ||||||
|  | //! - **hyper-011**: Provides support for hyper's old typed headers. | ||||||
|  | //! | ||||||
|  | //! | ||||||
| //! [hyper]: http://hyper.rs | //! [hyper]: http://hyper.rs | ||||||
| //! [client]: ./struct.Client.html | //! [client]: ./struct.Client.html | ||||||
| //! [response]: ./struct.Response.html | //! [response]: ./struct.Response.html | ||||||
| @@ -124,6 +134,7 @@ | |||||||
| //! [builder]: ./struct.RequestBuilder.html | //! [builder]: ./struct.RequestBuilder.html | ||||||
| //! [serde]: http://serde.rs | //! [serde]: http://serde.rs | ||||||
| //! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14 | //! [cookiejar_issue]: https://github.com/seanmonstar/reqwest/issues/14 | ||||||
|  | //! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section | ||||||
|  |  | ||||||
| extern crate base64; | extern crate base64; | ||||||
| extern crate bytes; | extern crate bytes; | ||||||
| @@ -134,12 +145,14 @@ extern crate http; | |||||||
| extern crate hyper; | extern crate hyper; | ||||||
| #[cfg(feature = "hyper-011")] | #[cfg(feature = "hyper-011")] | ||||||
| pub extern crate hyper_old_types as hyper_011; | pub extern crate hyper_old_types as hyper_011; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| extern crate hyper_tls; | extern crate hyper_tls; | ||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate log; | extern crate log; | ||||||
| extern crate libflate; | extern crate libflate; | ||||||
| extern crate mime; | extern crate mime; | ||||||
| extern crate mime_guess; | extern crate mime_guess; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| extern crate native_tls; | extern crate native_tls; | ||||||
| extern crate serde; | extern crate serde; | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| @@ -148,7 +161,7 @@ extern crate serde_derive; | |||||||
| extern crate serde_json; | extern crate serde_json; | ||||||
| extern crate serde_urlencoded; | extern crate serde_urlencoded; | ||||||
| extern crate tokio; | extern crate tokio; | ||||||
| #[macro_use] | #[cfg_attr(feature = "default-tls", macro_use)] | ||||||
| extern crate tokio_io; | extern crate tokio_io; | ||||||
| extern crate url; | extern crate url; | ||||||
| extern crate uuid; | extern crate uuid; | ||||||
| @@ -167,6 +180,7 @@ pub use self::proxy::Proxy; | |||||||
| pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy}; | pub use self::redirect::{RedirectAction, RedirectAttempt, RedirectPolicy}; | ||||||
| pub use self::request::{Request, RequestBuilder}; | pub use self::request::{Request, RequestBuilder}; | ||||||
| pub use self::response::Response; | pub use self::response::Response; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| pub use self::tls::{Certificate, Identity}; | pub use self::tls::{Certificate, Identity}; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -176,6 +190,7 @@ mod error; | |||||||
|  |  | ||||||
| mod async_impl; | mod async_impl; | ||||||
| mod connect; | mod connect; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| mod connect_async; | mod connect_async; | ||||||
| mod body; | mod body; | ||||||
| mod client; | mod client; | ||||||
| @@ -184,6 +199,7 @@ mod proxy; | |||||||
| mod redirect; | mod redirect; | ||||||
| mod request; | mod request; | ||||||
| mod response; | mod response; | ||||||
|  | #[cfg(feature = "default-tls")] | ||||||
| mod tls; | mod tls; | ||||||
| mod wait; | mod wait; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user