diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index bb9d02b5..0886b27e 100755 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -29,7 +29,7 @@ default = ["accept", "connect", "uri"] accept = [] # enable connector services -connect = ["tokio/net"] +connect = [] # use openssl impls openssl = ["tls-openssl", "tokio-openssl"] @@ -53,7 +53,6 @@ derive_more = "0.99.5" futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] } http = { version = "0.2.3", optional = true } log = "0.4" -tokio = { version = "1", optional = true } # openssl tls-openssl = { package = "openssl", version = "0.10", optional = true } diff --git a/actix-tls/src/connect/resolve.rs b/actix-tls/src/connect/resolve.rs index b61ab7e5..211da387 100755 --- a/actix-tls/src/connect/resolve.rs +++ b/actix-tls/src/connect/resolve.rs @@ -1,13 +1,16 @@ use std::{ future::Future, + io, net::SocketAddr, pin::Pin, rc::Rc, task::{Context, Poll}, + vec::IntoIter, }; +use actix_rt::task::{spawn_blocking, JoinHandle}; use actix_service::{Service, ServiceFactory}; -use futures_core::future::LocalBoxFuture; +use futures_core::{future::LocalBoxFuture, ready}; use log::trace; use super::connect::{Address, Connect}; @@ -115,46 +118,24 @@ impl Resolver { Self::Custom(Rc::new(resolver)) } - async fn lookup( - &self, - req: &Connect, - ) -> Result, ConnectError> { - match self { - Self::Default => { - let host = req.host(); - // TODO: Connect should always return host with port if possible. - let host = if req - .host() - .splitn(2, ':') - .last() - .and_then(|p| p.parse::().ok()) - .map(|p| p == req.port()) - .unwrap_or(false) - { - host.to_string() - } else { - format!("{}:{}", host, req.port()) - }; + // look up with default resolver variant. + fn look_up(req: &Connect) -> JoinHandle>> { + let host = req.host(); + // TODO: Connect should always return host with port if possible. + let host = if req + .host() + .splitn(2, ':') + .last() + .and_then(|p| p.parse::().ok()) + .map(|p| p == req.port()) + .unwrap_or(false) + { + host.to_string() + } else { + format!("{}:{}", host, req.port()) + }; - let res = tokio::net::lookup_host(host) - .await - .map_err(|e| { - trace!( - "DNS resolver: failed to resolve host {:?} err: {}", - req.host(), - e - ); - ConnectError::Resolver(Box::new(e)) - })? - .collect(); - - Ok(res) - } - Self::Custom(resolver) => resolver - .lookup(req.host(), req.port()) - .await - .map_err(ConnectError::Resolver), - } + spawn_blocking(move || std::net::ToSocketAddrs::to_socket_addrs(&host)) } } @@ -175,31 +156,41 @@ impl Service> for Resolver { } else { trace!("DNS resolver: resolving host {:?}", req.host()); - let resolver = self.clone(); - ResolverFuture::Lookup(Box::pin(async move { - let addrs = resolver.lookup(&req).await?; - - let req = req.set_addrs(addrs); - - trace!( - "DNS resolver: host {:?} resolved to {:?}", - req.host(), - req.addrs() - ); - - if req.addr.is_none() { - Err(ConnectError::NoRecords) - } else { - Ok(req) + match self { + Self::Default => { + let fut = Self::look_up(&req); + ResolverFuture::LookUp(fut, Some(req)) } - })) + + Self::Custom(resolver) => { + let resolver = Rc::clone(&resolver); + ResolverFuture::LookupCustom(Box::pin(async move { + let addrs = resolver + .lookup(req.host(), req.port()) + .await + .map_err(ConnectError::Resolver)?; + + let req = req.set_addrs(addrs); + + if req.addr.is_none() { + Err(ConnectError::NoRecords) + } else { + Ok(req) + } + })) + } + } } } } pub enum ResolverFuture { Connected(Option>), - Lookup(LocalBoxFuture<'static, Result, ConnectError>>), + LookUp( + JoinHandle>>, + Option>, + ), + LookupCustom(LocalBoxFuture<'static, Result, ConnectError>>), } impl Future for ResolverFuture { @@ -210,7 +201,39 @@ impl Future for ResolverFuture { Self::Connected(conn) => Poll::Ready(Ok(conn .take() .expect("ResolverFuture polled after finished"))), - Self::Lookup(fut) => fut.as_mut().poll(cx), + Self::LookUp(fut, req) => { + let res = match ready!(Pin::new(fut).poll(cx)) { + Ok(Ok(res)) => Ok(res), + Ok(Err(e)) => Err(ConnectError::Resolver(Box::new(e))), + Err(e) => Err(ConnectError::Io(e.into())), + }; + + let req = req.take().unwrap(); + + let addrs = res.map_err(|e| { + trace!( + "DNS resolver: failed to resolve host {:?} err: {:?}", + req.host(), + e + ); + e + })?; + + let req = req.set_addrs(addrs); + + trace!( + "DNS resolver: host {:?} resolved to {:?}", + req.host(), + req.addrs() + ); + + if req.addr.is_none() { + Poll::Ready(Err(ConnectError::NoRecords)) + } else { + Poll::Ready(Ok(req)) + } + } + Self::LookupCustom(fut) => fut.as_mut().poll(cx), } } }