Re-enable trust-dns optional feature (#787)
This commit is contained in:
		| @@ -45,7 +45,7 @@ brotli = ["async-compression", "async-compression/brotli"] | |||||||
|  |  | ||||||
| json = ["serde_json"] | json = ["serde_json"] | ||||||
|  |  | ||||||
| #trust-dns = ["trust-dns-resolver"] | trust-dns = ["trust-dns-resolver"] | ||||||
|  |  | ||||||
| stream = [] | stream = [] | ||||||
|  |  | ||||||
| @@ -113,7 +113,7 @@ async-compression = { version = "0.3.0", default-features = false, features = [" | |||||||
| tokio-socks = { version = "0.2", optional = true } | tokio-socks = { version = "0.2", optional = true } | ||||||
|  |  | ||||||
| ## trust-dns | ## trust-dns | ||||||
| #trust-dns-resolver = { version = "0.11", optional = true } | trust-dns-resolver = { version = "0.19", optional = true } | ||||||
|  |  | ||||||
| [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] | [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] | ||||||
| env_logger = "0.6" | env_logger = "0.6" | ||||||
|   | |||||||
| @@ -19,8 +19,8 @@ use std::time::Duration; | |||||||
| use std::mem::MaybeUninit; | use std::mem::MaybeUninit; | ||||||
| use pin_project_lite::pin_project; | use pin_project_lite::pin_project; | ||||||
|  |  | ||||||
| //#[cfg(feature = "trust-dns")] | #[cfg(feature = "trust-dns")] | ||||||
| //use crate::dns::TrustDnsResolver; | use crate::dns::TrustDnsResolver; | ||||||
| use crate::proxy::{Proxy, ProxyScheme}; | use crate::proxy::{Proxy, ProxyScheme}; | ||||||
| use crate::error::BoxError; | use crate::error::BoxError; | ||||||
| #[cfg(feature = "default-tls")] | #[cfg(feature = "default-tls")] | ||||||
| @@ -28,9 +28,9 @@ use self::native_tls_conn::NativeTlsConn; | |||||||
| #[cfg(feature = "rustls-tls")] | #[cfg(feature = "rustls-tls")] | ||||||
| use self::rustls_tls_conn::RustlsTlsConn; | use self::rustls_tls_conn::RustlsTlsConn; | ||||||
|  |  | ||||||
| //#[cfg(feature = "trust-dns")] | #[cfg(feature = "trust-dns")] | ||||||
| //type HttpConnector = hyper::client::HttpConnector<TrustDnsResolver>; | type HttpConnector = hyper::client::HttpConnector<TrustDnsResolver>; | ||||||
| //#[cfg(not(feature = "trust-dns"))] | #[cfg(not(feature = "trust-dns"))] | ||||||
| type HttpConnector = hyper::client::HttpConnector; | type HttpConnector = hyper::client::HttpConnector; | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| @@ -413,14 +413,14 @@ fn into_uri(scheme: Scheme, host: Authority) -> Uri { | |||||||
|         .expect("scheme and authority is valid Uri") |         .expect("scheme and authority is valid Uri") | ||||||
| } | } | ||||||
|  |  | ||||||
| //#[cfg(feature = "trust-dns")] | #[cfg(feature = "trust-dns")] | ||||||
| //fn http_connector() -> crate::Result<HttpConnector> { | fn http_connector() -> crate::Result<HttpConnector> { | ||||||
| //    TrustDnsResolver::new() |     TrustDnsResolver::new() | ||||||
| //        .map(HttpConnector::new_with_resolver) |         .map(HttpConnector::new_with_resolver) | ||||||
| //        .map_err(crate::error::dns_system_conf) |         .map_err(crate::error::builder) | ||||||
| //} | } | ||||||
|  |  | ||||||
| //#[cfg(not(feature = "trust-dns"))] | #[cfg(not(feature = "trust-dns"))] | ||||||
| fn http_connector() -> crate::Result<HttpConnector> { | fn http_connector() -> crate::Result<HttpConnector> { | ||||||
|     Ok(HttpConnector::new()) |     Ok(HttpConnector::new()) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								src/dns.rs
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								src/dns.rs
									
									
									
									
									
								
							| @@ -1,76 +1,91 @@ | |||||||
| use std::future::Future; | use std::future::Future; | ||||||
| use std::net::IpAddr; | use std::pin::Pin; | ||||||
| use std::sync::{Arc, Mutex, Once}; | use std::sync::Arc; | ||||||
| use std::{io, vec}; | use std::task::{self, Poll}; | ||||||
|  | use std::io; | ||||||
|  |  | ||||||
| use futures_util::future; |  | ||||||
| use hyper::client::connect::dns as hyper_dns; | use hyper::client::connect::dns as hyper_dns; | ||||||
| use tokio; | use hyper::service::Service; | ||||||
| use trust_dns_resolver::{system_conf, AsyncResolver, BackgroundLookupIp}; | use tokio::sync::Mutex; | ||||||
|  | use trust_dns_resolver::{ | ||||||
|  |     config::{ResolverConfig, ResolverOpts}, | ||||||
|  |     lookup_ip::LookupIpIntoIter, | ||||||
|  |     system_conf, AsyncResolver, TokioConnection, TokioConnectionProvider, | ||||||
|  | }; | ||||||
|  |  | ||||||
| // If instead the type were just `AsyncResolver`, it breaks the default recursion limit | use crate::error::BoxError; | ||||||
| // 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. | type SharedResolver = Arc<AsyncResolver<TokioConnection, TokioConnectionProvider>>; | ||||||
| // |  | ||||||
| // "Erasing" the internal resolver type saves us from this limit. | lazy_static! { | ||||||
| type ErasedResolver = Box<dyn Fn(hyper_dns::Name) -> BackgroundLookupIp + Send + Sync>; |     static ref SYSTEM_CONF: io::Result<(ResolverConfig, ResolverOpts)> = system_conf::read_system_conf(); | ||||||
| type Background = Box<dyn Future<Item = (), Error = ()> + Send>; | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| pub(crate) struct TrustDnsResolver { | pub(crate) struct TrustDnsResolver { | ||||||
|     inner: Arc<Inner>, |     state: Arc<Mutex<State>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| struct Inner { | enum State { | ||||||
|     background: Mutex<Option<Background>>, |     Init, | ||||||
|     once: Once, |     Ready(SharedResolver), | ||||||
|     resolver: ErasedResolver, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TrustDnsResolver { | impl TrustDnsResolver { | ||||||
|     pub(crate) fn new() -> io::Result<Self> { |     pub(crate) fn new() -> io::Result<Self> { | ||||||
|         let (conf, opts) = system_conf::read_system_conf()?; |         SYSTEM_CONF.as_ref().map_err(|e| { | ||||||
|         let (resolver, bg) = AsyncResolver::new(conf, opts); |             io::Error::new(e.kind(), format!("error reading DNS system conf: {}", e)) | ||||||
|  |         })?; | ||||||
|         let resolver: ErasedResolver = Box::new(move |name| resolver.lookup_ip(name.as_str())); |  | ||||||
|         let background = Mutex::new(Some(Box::new(bg) as Background)); |  | ||||||
|         let once = Once::new(); |  | ||||||
|  |  | ||||||
|  |         // At this stage, we might not have been called in the context of a | ||||||
|  |         // Tokio Runtime, so we must delay the actual construction of the | ||||||
|  |         // resolver. | ||||||
|         Ok(TrustDnsResolver { |         Ok(TrustDnsResolver { | ||||||
|             inner: Arc::new(Inner { |             state: Arc::new(Mutex::new(State::Init)), | ||||||
|                 background, |  | ||||||
|                 once, |  | ||||||
|                 resolver, |  | ||||||
|             }), |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl hyper_dns::Resolve for TrustDnsResolver { | impl Service<hyper_dns::Name> for TrustDnsResolver { | ||||||
|     type Addrs = vec::IntoIter<IpAddr>; |     type Response = LookupIpIntoIter; | ||||||
|     type Future = Box<dyn Future<Output = Result<Self::Addrs, io::Error>> + Send>; |     type Error = BoxError; | ||||||
|  |     type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; | ||||||
|  |  | ||||||
|     fn resolve(&self, name: hyper_dns::Name) -> Self::Future { |     fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> { | ||||||
|         let inner = self.inner.clone(); |         Poll::Ready(Ok(())) | ||||||
|         Box::new(future::lazy(move || { |     } | ||||||
|             inner.once.call_once(|| { |  | ||||||
|                 // 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. |  | ||||||
|                 let bg = inner |  | ||||||
|                     .background |  | ||||||
|                     .lock() |  | ||||||
|                     .expect("resolver background lock") |  | ||||||
|                     .take() |  | ||||||
|                     .expect("background only taken once"); |  | ||||||
|  |  | ||||||
|                 tokio::spawn(bg); |     fn call(&mut self, name: hyper_dns::Name) -> Self::Future { | ||||||
|             }); |         let resolver = self.clone(); | ||||||
|  |         Box::pin(async move { | ||||||
|  |             let mut lock = resolver.state.lock().await; | ||||||
|  |  | ||||||
|             (inner.resolver)(name) |             let resolver = match &*lock { | ||||||
|                 .map(|lookup| lookup.iter().collect::<Vec<_>>().into_iter()) |                 State::Init => { | ||||||
|                 .map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string())) |                     let resolver = new_resolver(tokio::runtime::Handle::current()).await?; | ||||||
|         })) |                     *lock = State::Ready(resolver.clone()); | ||||||
|  |                     resolver | ||||||
|  |                 }, | ||||||
|  |                 State::Ready(resolver) => resolver.clone(), | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             // Don't keep lock once the resolver is constructed, otherwise | ||||||
|  |             // only one lookup could be done at a time. | ||||||
|  |             drop(lock); | ||||||
|  |  | ||||||
|  |             let lookup = resolver.lookup_ip(name.as_str()).await?; | ||||||
|  |             Ok(lookup.into_iter()) | ||||||
|  |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Takes a `Handle` argument as an indicator that it must be called from | ||||||
|  | /// within the context of a Tokio runtime. | ||||||
|  | async fn new_resolver(handle: tokio::runtime::Handle) -> Result<SharedResolver, BoxError> { | ||||||
|  |     let (config, opts) = SYSTEM_CONF | ||||||
|  |         .as_ref() | ||||||
|  |         .expect("can't construct TrustDnsResolver if SYSTEM_CONF is error") | ||||||
|  |         .clone(); | ||||||
|  |     let resolver = AsyncResolver::new(config, opts, handle).await?; | ||||||
|  |     Ok(Arc::new(resolver)) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -177,6 +177,8 @@ | |||||||
| //! - **json**: Provides serialization and deserialization for JSON bodies. | //! - **json**: Provides serialization and deserialization for JSON bodies. | ||||||
| //! - **stream**: Adds support for `futures::Stream`. | //! - **stream**: Adds support for `futures::Stream`. | ||||||
| //! - **socks**: Provides SOCKS5 proxy support. | //! - **socks**: Provides SOCKS5 proxy support. | ||||||
|  | //! - **trust-dns**: Enables a trust-dns async resolver instead of default | ||||||
|  | //!   threadpool using `getaddrinfo`. | ||||||
| //! | //! | ||||||
| //! | //! | ||||||
| //! [hyper]: http://hyper.rs | //! [hyper]: http://hyper.rs | ||||||
| @@ -188,8 +190,6 @@ | |||||||
| //! [redirect]: crate::redirect | //! [redirect]: crate::redirect | ||||||
| //! [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 | ||||||
| ////! - **trust-dns**: Enables a trust-dns async resolver instead of default |  | ||||||
| ////!   threadpool using `getaddrinfo`. |  | ||||||
|  |  | ||||||
| macro_rules! if_wasm { | macro_rules! if_wasm { | ||||||
|     ($($item:item)*) => {$( |     ($($item:item)*) => {$( | ||||||
| @@ -295,8 +295,8 @@ if_hyper! { | |||||||
|     mod connect; |     mod connect; | ||||||
|     #[cfg(feature = "cookies")] |     #[cfg(feature = "cookies")] | ||||||
|     pub mod cookie; |     pub mod cookie; | ||||||
|     //#[cfg(feature = "trust-dns")] |     #[cfg(feature = "trust-dns")] | ||||||
|     //mod dns; |     mod dns; | ||||||
|     mod proxy; |     mod proxy; | ||||||
|     pub mod redirect; |     pub mod redirect; | ||||||
|     #[cfg(feature = "__tls")] |     #[cfg(feature = "__tls")] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user