Replace getaddrinfo resolver with trust-dns-resolver
This commit is contained in:
		| @@ -27,7 +27,10 @@ serde = "1.0" | |||||||
| serde_json = "1.0" | serde_json = "1.0" | ||||||
| serde_urlencoded = "0.5" | serde_urlencoded = "0.5" | ||||||
| tokio = "0.1.7" | tokio = "0.1.7" | ||||||
|  | tokio-executor = "0.1.4" # a minimum version so trust-dns-resolver compiles | ||||||
| tokio-io = "0.1" | tokio-io = "0.1" | ||||||
|  | tokio-timer = "0.2.6" # a minimum version so trust-dns-resolver compiles | ||||||
|  | trust-dns-resolver = "0.10" | ||||||
| url = "1.2" | url = "1.2" | ||||||
| uuid = { version = "0.7", features = ["v4"] } | uuid = { version = "0.7", features = ["v4"] } | ||||||
| hyper-rustls = { version = "0.15", optional = true } | hyper-rustls = { version = "0.15", optional = true } | ||||||
|   | |||||||
| @@ -60,7 +60,6 @@ struct Config { | |||||||
|     identity: Option<Identity>, |     identity: Option<Identity>, | ||||||
|     #[cfg(feature = "tls")] |     #[cfg(feature = "tls")] | ||||||
|     tls: TLSBackend, |     tls: TLSBackend, | ||||||
|     dns_threads: usize, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl ClientBuilder { | impl ClientBuilder { | ||||||
| @@ -88,7 +87,6 @@ impl ClientBuilder { | |||||||
|                 identity: None, |                 identity: None, | ||||||
|                 #[cfg(feature = "tls")] |                 #[cfg(feature = "tls")] | ||||||
|                 tls: TLSBackend::default(), |                 tls: TLSBackend::default(), | ||||||
|                 dns_threads: 4, |  | ||||||
|             }, |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -131,7 +129,7 @@ impl ClientBuilder { | |||||||
|                         tls.identity(id); |                         tls.identity(id); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     Connector::new_default_tls(config.dns_threads, tls, proxies.clone())? |                     Connector::new_default_tls(tls, proxies.clone())? | ||||||
|                 }, |                 }, | ||||||
|                 #[cfg(feature = "rustls-tls")] |                 #[cfg(feature = "rustls-tls")] | ||||||
|                 TLSBackend::Rustls => { |                 TLSBackend::Rustls => { | ||||||
| @@ -188,12 +186,12 @@ impl ClientBuilder { | |||||||
|                         tls.set_single_client_cert(certs, key); |                         tls.set_single_client_cert(certs, key); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     Connector::new_rustls_tls(config.dns_threads, tls, proxies.clone())? |                     Connector::new_rustls_tls(tls, proxies.clone())? | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             #[cfg(not(feature = "tls"))] |             #[cfg(not(feature = "tls"))] | ||||||
|             Connector::new(config.dns_threads, proxies.clone()) |             Connector::new(proxies.clone()) | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         let hyper_client = ::hyper::Client::builder() |         let hyper_client = ::hyper::Client::builder() | ||||||
| @@ -327,9 +325,9 @@ impl ClientBuilder { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Set number of DNS threads. |     #[doc(hidden)] | ||||||
|     pub fn dns_threads(mut self, threads: usize) -> ClientBuilder { |     #[deprecated(note = "DNS no longer uses blocking threads")] | ||||||
|         self.config.dns_threads = threads; |     pub fn dns_threads(self, _threads: usize) -> ClientBuilder { | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -281,13 +281,6 @@ impl ClientBuilder { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Set the number of threads to use for DNS |  | ||||||
|     /// |  | ||||||
|     /// Default is 4 |  | ||||||
|     pub fn dns_threads(self, threads: usize) -> ClientBuilder { |  | ||||||
|         self.with_inner(|inner| inner.dns_threads(threads)) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn with_inner<F>(mut self, func: F) -> ClientBuilder |     fn with_inner<F>(mut self, func: F) -> ClientBuilder | ||||||
|     where |     where | ||||||
|         F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder, |         F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder, | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| use futures::Future; | use futures::Future; | ||||||
| use http::uri::Scheme; | use http::uri::Scheme; | ||||||
| use hyper::client::{HttpConnector}; |  | ||||||
| use hyper::client::connect::{Connect, Connected, Destination}; | use hyper::client::connect::{Connect, Connected, Destination}; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  |  | ||||||
| @@ -14,8 +13,11 @@ use bytes::BufMut; | |||||||
| use std::io; | use std::io; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
|  |  | ||||||
|  | use dns::TrustDnsResolver; | ||||||
| use Proxy; | use Proxy; | ||||||
|  |  | ||||||
|  | type HttpConnector = ::hyper::client::HttpConnector<TrustDnsResolver>; | ||||||
|  |  | ||||||
|  |  | ||||||
| pub(crate) struct Connector { | pub(crate) struct Connector { | ||||||
|     proxies: Arc<Vec<Proxy>>, |     proxies: Arc<Vec<Proxy>>, | ||||||
| @@ -33,8 +35,8 @@ enum Inner { | |||||||
|  |  | ||||||
| impl Connector { | impl Connector { | ||||||
|     #[cfg(not(feature = "tls"))] |     #[cfg(not(feature = "tls"))] | ||||||
|     pub(crate) fn new(threads: usize, proxies: Arc<Vec<Proxy>>) -> Connector { |     pub(crate) fn new(proxies: Arc<Vec<Proxy>>) -> Connector { | ||||||
|         let http = HttpConnector::new(threads); |         let http = http_connector(); | ||||||
|         Connector { |         Connector { | ||||||
|             proxies, |             proxies, | ||||||
|             inner: Inner::Http(http) |             inner: Inner::Http(http) | ||||||
| @@ -42,10 +44,10 @@ impl Connector { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[cfg(feature = "default-tls")] |     #[cfg(feature = "default-tls")] | ||||||
|     pub(crate) fn new_default_tls(threads: usize, tls: TlsConnectorBuilder, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { |     pub(crate) fn new_default_tls(tls: TlsConnectorBuilder, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { | ||||||
|         let tls = try_!(tls.build()); |         let tls = try_!(tls.build()); | ||||||
|  |  | ||||||
|         let mut http = HttpConnector::new(threads); |         let mut http = http_connector(); | ||||||
|         http.enforce_http(false); |         http.enforce_http(false); | ||||||
|         let http = ::hyper_tls::HttpsConnector::from((http, tls.clone())); |         let http = ::hyper_tls::HttpsConnector::from((http, tls.clone())); | ||||||
|  |  | ||||||
| @@ -56,8 +58,8 @@ impl Connector { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[cfg(feature = "rustls-tls")] |     #[cfg(feature = "rustls-tls")] | ||||||
|     pub(crate) fn new_rustls_tls(threads: usize, tls: rustls::ClientConfig, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { |     pub(crate) fn new_rustls_tls(tls: rustls::ClientConfig, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> { | ||||||
|         let mut http = HttpConnector::new(threads); |         let mut http = http_connector(); | ||||||
|         http.enforce_http(false); |         http.enforce_http(false); | ||||||
|         let http = ::hyper_rustls::HttpsConnector::from((http, tls.clone())); |         let http = ::hyper_rustls::HttpsConnector::from((http, tls.clone())); | ||||||
|  |  | ||||||
| @@ -68,6 +70,11 @@ impl Connector { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn http_connector() -> HttpConnector { | ||||||
|  |     let http = HttpConnector::new_with_resolver(TrustDnsResolver::new()); | ||||||
|  |     http | ||||||
|  | } | ||||||
|  |  | ||||||
| impl Connect for Connector { | impl Connect for Connector { | ||||||
|     type Transport = Conn; |     type Transport = Conn; | ||||||
|     type Error = io::Error; |     type Error = io::Error; | ||||||
|   | |||||||
							
								
								
									
										73
									
								
								src/dns.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/dns.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | use std::io; | ||||||
|  | use std::sync::{Arc, Mutex}; | ||||||
|  |  | ||||||
|  | use futures::{future, Future}; | ||||||
|  | use hyper::client::connect::dns as hyper_dns; | ||||||
|  | use trust_dns_resolver::AsyncResolver; | ||||||
|  |  | ||||||
|  | // If instead the type were just `AsyncResolver`, it breaks the default recursion limit | ||||||
|  | // for the compiler to determine if `reqwest::Client` is `Send`. This is because `AsyncResolver` | ||||||
|  | // has **a lot** of internal generic types that pushes us over the limit. | ||||||
|  | // | ||||||
|  | // "Erasing" the internal resolver type saves us from this limit. | ||||||
|  | type ErasedResolver = Box<Fn(hyper_dns::Name) -> ::trust_dns_resolver::BackgroundLookupIp + Send + Sync>; | ||||||
|  |  | ||||||
|  | #[derive(Clone)] | ||||||
|  | pub(crate) struct TrustDnsResolver { | ||||||
|  |     inner: Arc<Mutex<Option<ErasedResolver>>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl TrustDnsResolver { | ||||||
|  |     pub(crate) fn new() -> Self { | ||||||
|  |         TrustDnsResolver { | ||||||
|  |             inner: Arc::new(Mutex::new(None)), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl hyper_dns::Resolve for TrustDnsResolver { | ||||||
|  |     type Addrs = ::std::vec::IntoIter<::std::net::IpAddr>; | ||||||
|  |     type Future = Box<Future<Item=Self::Addrs, Error=io::Error> + Send>; | ||||||
|  |  | ||||||
|  |     fn resolve(&self, name: hyper_dns::Name) -> Self::Future { | ||||||
|  |         let inner = self.inner.clone(); | ||||||
|  |         Box::new(future::lazy(move || { | ||||||
|  |             let mut inner = inner.lock().expect("lock resolver"); | ||||||
|  |             if inner.is_none() { | ||||||
|  |                 // The `bg` (background) future needs to be spawned onto an executor, | ||||||
|  |                 // but a `reqwest::Client` may be constructed before an executor is ready. | ||||||
|  |                 // So, the `bg` future cannot be spawned *until* the executor starts to | ||||||
|  |                 // `poll` this future. | ||||||
|  |                 match AsyncResolver::from_system_conf() { | ||||||
|  |                     Ok((resolver, bg)) => { | ||||||
|  |                         ::tokio::spawn(bg); | ||||||
|  |                         *inner = Some(Box::new(move |name| { | ||||||
|  |                             resolver.lookup_ip(name.as_str()) | ||||||
|  |                         })); | ||||||
|  |                     }, | ||||||
|  |                     Err(err) => { | ||||||
|  |                         return future::Either::A( | ||||||
|  |                             future::err(io::Error::new(io::ErrorKind::Other, err.to_string())) | ||||||
|  |                         ); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             future::Either::B((inner | ||||||
|  |                 .as_mut() | ||||||
|  |                 .expect("resolver is set"))(name) | ||||||
|  |                 //.lookup_ip(name.as_str()) | ||||||
|  |                 .map(|lookup| { | ||||||
|  |                     lookup | ||||||
|  |                         .iter() | ||||||
|  |                         .collect::<Vec<_>>() | ||||||
|  |                         .into_iter() | ||||||
|  |                 }) | ||||||
|  |                 .map_err(|err| { | ||||||
|  |                     io::Error::new(io::ErrorKind::Other, err.to_string()) | ||||||
|  |                 })) | ||||||
|  |         })) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -163,6 +163,7 @@ extern crate serde_urlencoded; | |||||||
| extern crate tokio; | extern crate tokio; | ||||||
| #[cfg_attr(feature = "default-tls", macro_use)] | #[cfg_attr(feature = "default-tls", macro_use)] | ||||||
| extern crate tokio_io; | extern crate tokio_io; | ||||||
|  | extern crate trust_dns_resolver; | ||||||
| extern crate url; | extern crate url; | ||||||
| extern crate uuid; | extern crate uuid; | ||||||
|  |  | ||||||
| @@ -203,6 +204,7 @@ mod connect; | |||||||
| mod connect_async; | mod connect_async; | ||||||
| mod body; | mod body; | ||||||
| mod client; | mod client; | ||||||
|  | mod dns; | ||||||
| mod into_url; | mod into_url; | ||||||
| mod proxy; | mod proxy; | ||||||
| mod redirect; | mod redirect; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user