Replace getaddrinfo resolver with trust-dns-resolver
This commit is contained in:
@@ -27,7 +27,10 @@ serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_urlencoded = "0.5"
|
||||
tokio = "0.1.7"
|
||||
tokio-executor = "0.1.4" # a minimum version so trust-dns-resolver compiles
|
||||
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"
|
||||
uuid = { version = "0.7", features = ["v4"] }
|
||||
hyper-rustls = { version = "0.15", optional = true }
|
||||
|
||||
@@ -60,7 +60,6 @@ struct Config {
|
||||
identity: Option<Identity>,
|
||||
#[cfg(feature = "tls")]
|
||||
tls: TLSBackend,
|
||||
dns_threads: usize,
|
||||
}
|
||||
|
||||
impl ClientBuilder {
|
||||
@@ -88,7 +87,6 @@ impl ClientBuilder {
|
||||
identity: None,
|
||||
#[cfg(feature = "tls")]
|
||||
tls: TLSBackend::default(),
|
||||
dns_threads: 4,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -131,7 +129,7 @@ impl ClientBuilder {
|
||||
tls.identity(id);
|
||||
}
|
||||
|
||||
Connector::new_default_tls(config.dns_threads, tls, proxies.clone())?
|
||||
Connector::new_default_tls(tls, proxies.clone())?
|
||||
},
|
||||
#[cfg(feature = "rustls-tls")]
|
||||
TLSBackend::Rustls => {
|
||||
@@ -188,12 +186,12 @@ impl ClientBuilder {
|
||||
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"))]
|
||||
Connector::new(config.dns_threads, proxies.clone())
|
||||
Connector::new(proxies.clone())
|
||||
};
|
||||
|
||||
let hyper_client = ::hyper::Client::builder()
|
||||
@@ -327,9 +325,9 @@ impl ClientBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set number of DNS threads.
|
||||
pub fn dns_threads(mut self, threads: usize) -> ClientBuilder {
|
||||
self.config.dns_threads = threads;
|
||||
#[doc(hidden)]
|
||||
#[deprecated(note = "DNS no longer uses blocking threads")]
|
||||
pub fn dns_threads(self, _threads: usize) -> ClientBuilder {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,13 +281,6 @@ impl ClientBuilder {
|
||||
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
|
||||
where
|
||||
F: FnOnce(async_impl::ClientBuilder) -> async_impl::ClientBuilder,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use futures::Future;
|
||||
use http::uri::Scheme;
|
||||
use hyper::client::{HttpConnector};
|
||||
use hyper::client::connect::{Connect, Connected, Destination};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
@@ -14,8 +13,11 @@ use bytes::BufMut;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use dns::TrustDnsResolver;
|
||||
use Proxy;
|
||||
|
||||
type HttpConnector = ::hyper::client::HttpConnector<TrustDnsResolver>;
|
||||
|
||||
|
||||
pub(crate) struct Connector {
|
||||
proxies: Arc<Vec<Proxy>>,
|
||||
@@ -33,8 +35,8 @@ enum Inner {
|
||||
|
||||
impl Connector {
|
||||
#[cfg(not(feature = "tls"))]
|
||||
pub(crate) fn new(threads: usize, proxies: Arc<Vec<Proxy>>) -> Connector {
|
||||
let http = HttpConnector::new(threads);
|
||||
pub(crate) fn new(proxies: Arc<Vec<Proxy>>) -> Connector {
|
||||
let http = http_connector();
|
||||
Connector {
|
||||
proxies,
|
||||
inner: Inner::Http(http)
|
||||
@@ -42,10 +44,10 @@ impl Connector {
|
||||
}
|
||||
|
||||
#[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 mut http = HttpConnector::new(threads);
|
||||
let mut http = http_connector();
|
||||
http.enforce_http(false);
|
||||
let http = ::hyper_tls::HttpsConnector::from((http, tls.clone()));
|
||||
|
||||
@@ -56,8 +58,8 @@ impl Connector {
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustls-tls")]
|
||||
pub(crate) fn new_rustls_tls(threads: usize, tls: rustls::ClientConfig, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> {
|
||||
let mut http = HttpConnector::new(threads);
|
||||
pub(crate) fn new_rustls_tls(tls: rustls::ClientConfig, proxies: Arc<Vec<Proxy>>) -> ::Result<Connector> {
|
||||
let mut http = http_connector();
|
||||
http.enforce_http(false);
|
||||
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 {
|
||||
type Transport = Conn;
|
||||
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;
|
||||
#[cfg_attr(feature = "default-tls", macro_use)]
|
||||
extern crate tokio_io;
|
||||
extern crate trust_dns_resolver;
|
||||
extern crate url;
|
||||
extern crate uuid;
|
||||
|
||||
@@ -203,6 +204,7 @@ mod connect;
|
||||
mod connect_async;
|
||||
mod body;
|
||||
mod client;
|
||||
mod dns;
|
||||
mod into_url;
|
||||
mod proxy;
|
||||
mod redirect;
|
||||
|
||||
Reference in New Issue
Block a user