@@ -13,7 +13,7 @@ use http::header::{
|
||||
};
|
||||
use http::uri::Scheme;
|
||||
use http::Uri;
|
||||
use hyper::client::ResponseFuture;
|
||||
use hyper::client::{HttpConnector, ResponseFuture};
|
||||
#[cfg(feature = "native-tls-crate")]
|
||||
use native_tls_crate::TlsConnector;
|
||||
use pin_project_lite::pin_project;
|
||||
@@ -28,9 +28,12 @@ use super::decoder::Accepts;
|
||||
use super::request::{Request, RequestBuilder};
|
||||
use super::response::Response;
|
||||
use super::Body;
|
||||
use crate::connect::{Connector, HttpConnector};
|
||||
use crate::connect::Connector;
|
||||
#[cfg(feature = "cookies")]
|
||||
use crate::cookie;
|
||||
#[cfg(feature = "trust-dns")]
|
||||
use crate::dns::trust_dns::TrustDnsResolver;
|
||||
use crate::dns::{gai::GaiResolver, DnsResolverWithOverrides, DynResolver, Resolve};
|
||||
use crate::error;
|
||||
use crate::into_url::{expect_uri, try_uri};
|
||||
use crate::redirect::{self, remove_sensitive_headers};
|
||||
@@ -121,6 +124,7 @@ struct Config {
|
||||
error: Option<crate::Error>,
|
||||
https_only: bool,
|
||||
dns_overrides: HashMap<String, Vec<SocketAddr>>,
|
||||
dns_resolver: Option<Arc<dyn Resolve>>,
|
||||
}
|
||||
|
||||
impl Default for ClientBuilder {
|
||||
@@ -188,6 +192,7 @@ impl ClientBuilder {
|
||||
cookie_store: None,
|
||||
https_only: false,
|
||||
dns_overrides: HashMap::new(),
|
||||
dns_resolver: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -217,25 +222,23 @@ impl ClientBuilder {
|
||||
headers.get(USER_AGENT).cloned()
|
||||
}
|
||||
|
||||
let http = match config.trust_dns {
|
||||
false => {
|
||||
if config.dns_overrides.is_empty() {
|
||||
HttpConnector::new_gai()
|
||||
} else {
|
||||
HttpConnector::new_gai_with_overrides(config.dns_overrides)
|
||||
}
|
||||
}
|
||||
let mut resolver: Arc<dyn Resolve> = match config.trust_dns {
|
||||
false => Arc::new(GaiResolver::new()),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
true => {
|
||||
if config.dns_overrides.is_empty() {
|
||||
HttpConnector::new_trust_dns()?
|
||||
} else {
|
||||
HttpConnector::new_trust_dns_with_overrides(config.dns_overrides)?
|
||||
}
|
||||
}
|
||||
true => Arc::new(TrustDnsResolver::new().map_err(crate::error::builder)?),
|
||||
#[cfg(not(feature = "trust-dns"))]
|
||||
true => unreachable!("trust-dns shouldn't be enabled unless the feature is"),
|
||||
};
|
||||
if let Some(dns_resolver) = config.dns_resolver {
|
||||
resolver = dns_resolver;
|
||||
}
|
||||
if !config.dns_overrides.is_empty() {
|
||||
resolver = Arc::new(DnsResolverWithOverrides::new(
|
||||
resolver,
|
||||
config.dns_overrides,
|
||||
));
|
||||
}
|
||||
let http = HttpConnector::new_with_resolver(DynResolver::new(resolver));
|
||||
|
||||
#[cfg(feature = "__tls")]
|
||||
match config.tls {
|
||||
@@ -1340,6 +1343,16 @@ impl ClientBuilder {
|
||||
.insert(domain.to_string(), addrs.to_vec());
|
||||
self
|
||||
}
|
||||
|
||||
/// Override the DNS resolver implementation.
|
||||
///
|
||||
/// Pass an `Arc` wrapping a trait object implementing `Resolve`.
|
||||
/// Overrides for specific names passed to `resolve` and `resolve_to_addrs` will
|
||||
/// still be applied on top of this resolver.
|
||||
pub fn dns_resolver<R: Resolve + 'static>(mut self, resolver: Arc<R>) -> ClientBuilder {
|
||||
self.config.dns_resolver = Some(resolver as _);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
type HyperClient = hyper::Client<Connector, super::body::ImplStream>;
|
||||
|
||||
238
src/connect.rs
238
src/connect.rs
@@ -1,162 +1,31 @@
|
||||
use futures_util::future::Either;
|
||||
#[cfg(feature = "__tls")]
|
||||
use http::header::HeaderValue;
|
||||
use http::uri::{Authority, Scheme};
|
||||
use http::Uri;
|
||||
use hyper::client::connect::{
|
||||
dns::{GaiResolver, Name},
|
||||
Connected, Connection,
|
||||
};
|
||||
use hyper::client::connect::{Connected, Connection};
|
||||
use hyper::service::Service;
|
||||
#[cfg(feature = "native-tls-crate")]
|
||||
use native_tls_crate::{TlsConnector, TlsConnectorBuilder};
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
|
||||
use pin_project_lite::pin_project;
|
||||
use std::io::IoSlice;
|
||||
use std::future::Future;
|
||||
use std::io::{self, IoSlice};
|
||||
use std::net::IpAddr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
use std::{collections::HashMap, io};
|
||||
use std::{future::Future, net::SocketAddr};
|
||||
|
||||
#[cfg(feature = "default-tls")]
|
||||
use self::native_tls_conn::NativeTlsConn;
|
||||
#[cfg(feature = "__rustls")]
|
||||
use self::rustls_tls_conn::RustlsTlsConn;
|
||||
#[cfg(feature = "trust-dns")]
|
||||
use crate::dns::TrustDnsResolver;
|
||||
use crate::dns::DynResolver;
|
||||
use crate::error::BoxError;
|
||||
use crate::proxy::{Proxy, ProxyScheme};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum HttpConnector {
|
||||
Gai(hyper::client::HttpConnector),
|
||||
GaiWithDnsOverrides(hyper::client::HttpConnector<DnsResolverWithOverrides<GaiResolver>>),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
TrustDns(hyper::client::HttpConnector<TrustDnsResolver>),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
TrustDnsWithOverrides(hyper::client::HttpConnector<DnsResolverWithOverrides<TrustDnsResolver>>),
|
||||
}
|
||||
|
||||
impl HttpConnector {
|
||||
pub(crate) fn new_gai() -> Self {
|
||||
Self::Gai(hyper::client::HttpConnector::new())
|
||||
}
|
||||
|
||||
pub(crate) fn new_gai_with_overrides(overrides: HashMap<String, Vec<SocketAddr>>) -> Self {
|
||||
let gai = hyper::client::connect::dns::GaiResolver::new();
|
||||
let overridden_resolver = DnsResolverWithOverrides::new(gai, overrides);
|
||||
Self::GaiWithDnsOverrides(hyper::client::HttpConnector::new_with_resolver(
|
||||
overridden_resolver,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(feature = "trust-dns")]
|
||||
pub(crate) fn new_trust_dns() -> crate::Result<HttpConnector> {
|
||||
TrustDnsResolver::new()
|
||||
.map(hyper::client::HttpConnector::new_with_resolver)
|
||||
.map(Self::TrustDns)
|
||||
.map_err(crate::error::builder)
|
||||
}
|
||||
|
||||
#[cfg(feature = "trust-dns")]
|
||||
pub(crate) fn new_trust_dns_with_overrides(
|
||||
overrides: HashMap<String, Vec<SocketAddr>>,
|
||||
) -> crate::Result<HttpConnector> {
|
||||
TrustDnsResolver::new()
|
||||
.map(|resolver| DnsResolverWithOverrides::new(resolver, overrides))
|
||||
.map(hyper::client::HttpConnector::new_with_resolver)
|
||||
.map(Self::TrustDnsWithOverrides)
|
||||
.map_err(crate::error::builder)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_http_connector {
|
||||
($(fn $name:ident(&mut self, $($par_name:ident: $par_type:ty),*)$( -> $return:ty)?;)+) => {
|
||||
#[allow(dead_code)]
|
||||
impl HttpConnector {
|
||||
$(
|
||||
fn $name(&mut self, $($par_name: $par_type),*)$( -> $return)? {
|
||||
match self {
|
||||
Self::Gai(resolver) => resolver.$name($($par_name),*),
|
||||
Self::GaiWithDnsOverrides(resolver) => resolver.$name($($par_name),*),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
Self::TrustDns(resolver) => resolver.$name($($par_name),*),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
Self::TrustDnsWithOverrides(resolver) => resolver.$name($($par_name),*),
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_http_connector! {
|
||||
fn set_local_address(&mut self, addr: Option<IpAddr>);
|
||||
fn enforce_http(&mut self, is_enforced: bool);
|
||||
fn set_nodelay(&mut self, nodelay: bool);
|
||||
fn set_keepalive(&mut self, dur: Option<Duration>);
|
||||
}
|
||||
|
||||
impl Service<Uri> for HttpConnector {
|
||||
type Response = <hyper::client::HttpConnector as Service<Uri>>::Response;
|
||||
type Error = <hyper::client::HttpConnector as Service<Uri>>::Error;
|
||||
#[cfg(feature = "trust-dns")]
|
||||
type Future =
|
||||
Either<
|
||||
Either<
|
||||
<hyper::client::HttpConnector as Service<Uri>>::Future,
|
||||
<hyper::client::HttpConnector<DnsResolverWithOverrides<GaiResolver>> as Service<
|
||||
Uri,
|
||||
>>::Future,
|
||||
>,
|
||||
Either<
|
||||
<hyper::client::HttpConnector<TrustDnsResolver> as Service<Uri>>::Future,
|
||||
<hyper::client::HttpConnector<DnsResolverWithOverrides<TrustDnsResolver>> as Service<Uri>>::Future
|
||||
>
|
||||
>;
|
||||
#[cfg(not(feature = "trust-dns"))]
|
||||
type Future =
|
||||
Either<
|
||||
Either<
|
||||
<hyper::client::HttpConnector as Service<Uri>>::Future,
|
||||
<hyper::client::HttpConnector<DnsResolverWithOverrides<GaiResolver>> as Service<
|
||||
Uri,
|
||||
>>::Future,
|
||||
>,
|
||||
Either<
|
||||
<hyper::client::HttpConnector as Service<Uri>>::Future,
|
||||
<hyper::client::HttpConnector as Service<Uri>>::Future,
|
||||
>,
|
||||
>;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
match self {
|
||||
Self::Gai(resolver) => resolver.poll_ready(cx),
|
||||
Self::GaiWithDnsOverrides(resolver) => resolver.poll_ready(cx),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
Self::TrustDns(resolver) => resolver.poll_ready(cx),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
Self::TrustDnsWithOverrides(resolver) => resolver.poll_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(&mut self, dst: Uri) -> Self::Future {
|
||||
match self {
|
||||
Self::Gai(resolver) => Either::Left(Either::Left(resolver.call(dst))),
|
||||
Self::GaiWithDnsOverrides(resolver) => Either::Left(Either::Right(resolver.call(dst))),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
Self::TrustDns(resolver) => Either::Right(Either::Left(resolver.call(dst))),
|
||||
#[cfg(feature = "trust-dns")]
|
||||
Self::TrustDnsWithOverrides(resolver) => {
|
||||
Either::Right(Either::Right(resolver.call(dst)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) type HttpConnector = hyper::client::HttpConnector<DynResolver>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Connector {
|
||||
@@ -960,103 +829,6 @@ mod socks {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod itertools {
|
||||
pub(crate) enum Either<A, B> {
|
||||
Left(A),
|
||||
Right(B),
|
||||
}
|
||||
|
||||
impl<A, B> Iterator for Either<A, B>
|
||||
where
|
||||
A: Iterator,
|
||||
B: Iterator<Item = <A as Iterator>::Item>,
|
||||
{
|
||||
type Item = <A as Iterator>::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
Either::Left(a) => a.next(),
|
||||
Either::Right(b) => b.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
pub(crate) struct WrappedResolverFuture<Fut> {
|
||||
#[pin]
|
||||
fut: Fut,
|
||||
}
|
||||
}
|
||||
|
||||
impl<Fut, FutOutput, FutError> std::future::Future for WrappedResolverFuture<Fut>
|
||||
where
|
||||
Fut: std::future::Future<Output = Result<FutOutput, FutError>>,
|
||||
FutOutput: Iterator<Item = SocketAddr>,
|
||||
{
|
||||
type Output = Result<itertools::Either<FutOutput, std::vec::IntoIter<SocketAddr>>, FutError>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.fut
|
||||
.poll(cx)
|
||||
.map(|result| result.map(itertools::Either::Left))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct DnsResolverWithOverrides<Resolver>
|
||||
where
|
||||
Resolver: Clone,
|
||||
{
|
||||
dns_resolver: Resolver,
|
||||
overrides: Arc<HashMap<String, Vec<SocketAddr>>>,
|
||||
}
|
||||
|
||||
impl<Resolver: Clone> DnsResolverWithOverrides<Resolver> {
|
||||
fn new(dns_resolver: Resolver, overrides: HashMap<String, Vec<SocketAddr>>) -> Self {
|
||||
DnsResolverWithOverrides {
|
||||
dns_resolver,
|
||||
overrides: Arc::new(overrides),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Resolver, Iter> Service<Name> for DnsResolverWithOverrides<Resolver>
|
||||
where
|
||||
Resolver: Service<Name, Response = Iter> + Clone,
|
||||
Iter: Iterator<Item = SocketAddr>,
|
||||
{
|
||||
type Response = itertools::Either<Iter, std::vec::IntoIter<SocketAddr>>;
|
||||
type Error = <Resolver as Service<Name>>::Error;
|
||||
type Future = Either<
|
||||
WrappedResolverFuture<<Resolver as Service<Name>>::Future>,
|
||||
futures_util::future::Ready<
|
||||
Result<itertools::Either<Iter, std::vec::IntoIter<SocketAddr>>, Self::Error>,
|
||||
>,
|
||||
>;
|
||||
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.dns_resolver.poll_ready(cx)
|
||||
}
|
||||
|
||||
fn call(&mut self, name: Name) -> Self::Future {
|
||||
match self.overrides.get(name.as_str()) {
|
||||
Some(dest) => {
|
||||
let fut = futures_util::future::ready(Ok(itertools::Either::Right(
|
||||
dest.clone().into_iter(),
|
||||
)));
|
||||
Either::Right(fut)
|
||||
}
|
||||
None => {
|
||||
let resolver_fut = self.dns_resolver.call(name);
|
||||
let y = WrappedResolverFuture { fut: resolver_fut };
|
||||
Either::Left(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod verbose {
|
||||
use hyper::client::connect::{Connected, Connection};
|
||||
use std::fmt;
|
||||
|
||||
32
src/dns/gai.rs
Normal file
32
src/dns/gai.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use futures_util::future::FutureExt;
|
||||
use hyper::client::connect::dns::{GaiResolver as HyperGaiResolver, Name};
|
||||
use hyper::service::Service;
|
||||
|
||||
use crate::dns::{Addrs, Resolve, Resolving};
|
||||
use crate::error::BoxError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GaiResolver(HyperGaiResolver);
|
||||
|
||||
impl GaiResolver {
|
||||
pub fn new() -> Self {
|
||||
Self(HyperGaiResolver::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GaiResolver {
|
||||
fn default() -> Self {
|
||||
GaiResolver::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve for GaiResolver {
|
||||
fn resolve(&self, name: Name) -> Resolving {
|
||||
let this = &mut self.0.clone();
|
||||
Box::pin(Service::<Name>::call(this, name).map(|result| {
|
||||
result
|
||||
.map(|addrs| -> Addrs { Box::new(addrs) })
|
||||
.map_err(|err| -> BoxError { Box::new(err) })
|
||||
}))
|
||||
}
|
||||
}
|
||||
9
src/dns/mod.rs
Normal file
9
src/dns/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
//! DNS resolution
|
||||
|
||||
pub use resolve::{Addrs, Resolve, Resolving};
|
||||
pub(crate) use resolve::{DnsResolverWithOverrides, DynResolver};
|
||||
|
||||
pub(crate) mod gai;
|
||||
pub(crate) mod resolve;
|
||||
#[cfg(feature = "trust-dns")]
|
||||
pub(crate) mod trust_dns;
|
||||
84
src/dns/resolve.rs
Normal file
84
src/dns/resolve.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use hyper::client::connect::dns::Name;
|
||||
use hyper::service::Service;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::error::BoxError;
|
||||
|
||||
/// Alias for an `Iterator` trait object over `SocketAddr`.
|
||||
pub type Addrs = Box<dyn Iterator<Item = SocketAddr> + Send>;
|
||||
|
||||
/// Alias for the `Future` type returned by a DNS resolver.
|
||||
pub type Resolving = Pin<Box<dyn Future<Output = Result<Addrs, BoxError>> + Send>>;
|
||||
|
||||
/// Trait for customizing DNS resolution in reqwest.
|
||||
pub trait Resolve: Send + Sync {
|
||||
/// Performs DNS resolution on a `Name`.
|
||||
/// The return type is a future containing an iterator of `SocketAddr`.
|
||||
///
|
||||
/// It differs from `tower_service::Service<Name>` in several ways:
|
||||
/// * It is assumed that `resolve` will always be ready to poll.
|
||||
/// * It does not need a mutable reference to `self`.
|
||||
/// * Since trait objects cannot make use of associated types, it requires
|
||||
/// wrapping the returned `Future` and its contained `Iterator` with `Box`.
|
||||
fn resolve(&self, name: Name) -> Resolving;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct DynResolver {
|
||||
resolver: Arc<dyn Resolve>,
|
||||
}
|
||||
|
||||
impl DynResolver {
|
||||
pub(crate) fn new(resolver: Arc<dyn Resolve>) -> Self {
|
||||
Self { resolver }
|
||||
}
|
||||
}
|
||||
|
||||
impl Service<Name> for DynResolver {
|
||||
type Response = Addrs;
|
||||
type Error = BoxError;
|
||||
type Future = Resolving;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, name: Name) -> Self::Future {
|
||||
self.resolver.resolve(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DnsResolverWithOverrides {
|
||||
dns_resolver: Arc<dyn Resolve>,
|
||||
overrides: Arc<HashMap<String, Vec<SocketAddr>>>,
|
||||
}
|
||||
|
||||
impl DnsResolverWithOverrides {
|
||||
pub(crate) fn new(
|
||||
dns_resolver: Arc<dyn Resolve>,
|
||||
overrides: HashMap<String, Vec<SocketAddr>>,
|
||||
) -> Self {
|
||||
DnsResolverWithOverrides {
|
||||
dns_resolver,
|
||||
overrides: Arc::new(overrides),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolve for DnsResolverWithOverrides {
|
||||
fn resolve(&self, name: Name) -> Resolving {
|
||||
match self.overrides.get(name.as_str()) {
|
||||
Some(dest) => {
|
||||
let addrs: Addrs = Box::new(dest.clone().into_iter());
|
||||
Box::pin(futures_util::future::ready(Ok(addrs)))
|
||||
}
|
||||
None => self.dns_resolver.resolve(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{self, Poll};
|
||||
//! DNS resolution via the [trust_dns_resolver](https://github.com/bluejekyll/trust-dns) crate
|
||||
|
||||
use hyper::client::connect::dns as hyper_dns;
|
||||
use hyper::service::Service;
|
||||
use hyper::client::connect::dns::Name;
|
||||
use once_cell::sync::Lazy;
|
||||
use tokio::sync::Mutex;
|
||||
pub use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
|
||||
use trust_dns_resolver::{
|
||||
config::{ResolverConfig, ResolverOpts},
|
||||
lookup_ip::LookupIpIntoIter,
|
||||
system_conf, AsyncResolver, TokioConnection, TokioConnectionProvider, TokioHandle,
|
||||
lookup_ip::LookupIpIntoIter, system_conf, AsyncResolver, TokioConnection,
|
||||
TokioConnectionProvider, TokioHandle,
|
||||
};
|
||||
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{Addrs, Resolve, Resolving};
|
||||
|
||||
use crate::error::BoxError;
|
||||
|
||||
type SharedResolver = Arc<AsyncResolver<TokioConnection, TokioConnectionProvider>>;
|
||||
@@ -22,22 +22,26 @@ type SharedResolver = Arc<AsyncResolver<TokioConnection, TokioConnectionProvider
|
||||
static SYSTEM_CONF: Lazy<io::Result<(ResolverConfig, ResolverOpts)>> =
|
||||
Lazy::new(|| system_conf::read_system_conf().map_err(io::Error::from));
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Wrapper around an `AsyncResolver`, which implements the `Resolve` trait.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct TrustDnsResolver {
|
||||
state: Arc<Mutex<State>>,
|
||||
}
|
||||
|
||||
pub(crate) struct SocketAddrs {
|
||||
struct SocketAddrs {
|
||||
iter: LookupIpIntoIter,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum State {
|
||||
Init,
|
||||
Ready(SharedResolver),
|
||||
}
|
||||
|
||||
impl TrustDnsResolver {
|
||||
pub(crate) fn new() -> io::Result<Self> {
|
||||
/// Create a new resolver with the default configuration,
|
||||
/// which reads from `/etc/resolve.conf`.
|
||||
pub fn new() -> io::Result<Self> {
|
||||
SYSTEM_CONF.as_ref().map_err(|e| {
|
||||
io::Error::new(e.kind(), format!("error reading DNS system conf: {}", e))
|
||||
})?;
|
||||
@@ -51,16 +55,8 @@ impl TrustDnsResolver {
|
||||
}
|
||||
}
|
||||
|
||||
impl Service<hyper_dns::Name> for TrustDnsResolver {
|
||||
type Response = SocketAddrs;
|
||||
type Error = BoxError;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||
|
||||
fn poll_ready(&mut self, _: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, name: hyper_dns::Name) -> Self::Future {
|
||||
impl Resolve for TrustDnsResolver {
|
||||
fn resolve(&self, name: Name) -> Resolving {
|
||||
let resolver = self.clone();
|
||||
Box::pin(async move {
|
||||
let mut lock = resolver.state.lock().await;
|
||||
@@ -79,9 +75,10 @@ impl Service<hyper_dns::Name> for TrustDnsResolver {
|
||||
drop(lock);
|
||||
|
||||
let lookup = resolver.lookup_ip(name.as_str()).await?;
|
||||
Ok(SocketAddrs {
|
||||
let addrs: Addrs = Box::new(SocketAddrs {
|
||||
iter: lookup.into_iter(),
|
||||
})
|
||||
});
|
||||
Ok(addrs)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -99,6 +96,13 @@ async fn new_resolver() -> Result<SharedResolver, BoxError> {
|
||||
.as_ref()
|
||||
.expect("can't construct TrustDnsResolver if SYSTEM_CONF is error")
|
||||
.clone();
|
||||
new_resolver_with_config(config, opts)
|
||||
}
|
||||
|
||||
fn new_resolver_with_config(
|
||||
config: ResolverConfig,
|
||||
opts: ResolverOpts,
|
||||
) -> Result<SharedResolver, BoxError> {
|
||||
let resolver = AsyncResolver::new(config, opts, TokioHandle)?;
|
||||
Ok(Arc::new(resolver))
|
||||
}
|
||||
@@ -309,8 +309,7 @@ if_hyper! {
|
||||
mod connect;
|
||||
#[cfg(feature = "cookies")]
|
||||
pub mod cookie;
|
||||
#[cfg(feature = "trust-dns")]
|
||||
mod dns;
|
||||
pub mod dns;
|
||||
mod proxy;
|
||||
pub mod redirect;
|
||||
#[cfg(feature = "__tls")]
|
||||
|
||||
Reference in New Issue
Block a user