1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-03-20 16:05:18 +01:00

244 lines
7.1 KiB
Rust
Raw Normal View History

use std::{
future::Future,
io,
net::SocketAddr,
pin::Pin,
rc::Rc,
task::{Context, Poll},
vec::IntoIter,
};
use actix_rt::task::{spawn_blocking, JoinHandle};
Migrate actix-net to std::future (#64) * Migrate actix-codec, actix-rt, and actix-threadpool to std::future * update to latest tokio alpha and futures-rs * Migrate actix-service to std::future, This is a squash of ~8 commits, since it included a lot of experimentation. To see the commits, look into the semtexzv/std-future-service-tmp branch. * update futures-rs and tokio * Migrate actix-threadpool to std::future (#59) * Migrate actix-threadpool to std::future * Cosmetic refactor - turn log::error! into log::warn! as it doesn't throw any error - add Clone and Copy impls for Cancelled making it cheap to operate with - apply rustfmt * Bump up crate version to 0.2.0 and pre-fill its changelog * Disable patching 'actix-threadpool' crate in global workspace as unnecessary * Revert patching and fix 'actix-rt' * Migrate actix-rt to std::future (#47) * remove Pin from Service::poll_ready(); simplify combinators api; make code compile * disable tests * update travis config * refactor naming * drop IntoFuture trait * Migrate actix-server to std::future (#50) Still not finished, this is more WIP, this is an aggregation of several commits, which can be found in semtexzv/std-future-server-tmp branch * update actix-server * rename Factor to ServiceFactory * start server worker in start mehtod * update actix-utils * remove IntoTransform trait * Migrate actix-server::ssl::nativetls to std futures (#61) * Refactor 'nativetls' module * Migrate 'actix-server-config' to std futures - remove "uds" feature - disable features by default * Switch NativeTlsAcceptor to use 'tokio-tls' crate * Bikeshed features names and remove unnecessary dependencies for 'actix-server-config' crate * update openssl impl * migrate actix-connect to std::future * migrate actix-ioframe to std::future * update version to alpha.1 * fix boxed service * migrate server rustls support * migratte openssl and rustls connecttors * store the thread's handle with arbiter (#62) * update ssl connect tests * restore service tests * update readme
2019-11-14 18:38:24 +06:00
use actix_service::{Service, ServiceFactory};
use futures_core::{future::LocalBoxFuture, ready};
use log::trace;
2018-09-10 19:16:46 -07:00
use super::connect::{Address, Connect};
use super::error::ConnectError;
2019-03-13 12:40:11 -07:00
2021-01-26 08:05:19 +00:00
/// DNS Resolver Service Factory
#[derive(Clone)]
pub struct ResolverFactory {
resolver: Resolver,
2018-09-10 19:16:46 -07:00
}
impl ResolverFactory {
pub fn new(resolver: Resolver) -> Self {
Self { resolver }
}
2019-03-13 22:51:31 -07:00
pub fn service(&self) -> Resolver {
self.resolver.clone()
2019-03-13 12:40:11 -07:00
}
}
impl<T: Address> ServiceFactory<Connect<T>> for ResolverFactory {
2019-03-13 15:37:12 -07:00
type Response = Connect<T>;
2019-03-13 12:40:11 -07:00
type Error = ConnectError;
type Config = ();
type Service = Resolver;
2019-03-13 12:40:11 -07:00
type InitError = ();
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
2019-03-13 12:40:11 -07:00
fn new_service(&self, _: ()) -> Self::Future {
let service = self.resolver.clone();
Box::pin(async { Ok(service) })
2019-03-13 12:40:11 -07:00
}
}
/// DNS Resolver Service
#[derive(Clone)]
pub enum Resolver {
Default,
Custom(Rc<dyn Resolve>),
2018-09-10 19:16:46 -07:00
}
2021-01-26 08:05:19 +00:00
/// An interface for custom async DNS resolvers.
///
2021-01-26 08:05:19 +00:00
/// # Usage
/// ```rust
/// use std::net::SocketAddr;
///
/// use actix_tls::connect::{Resolve, Resolver};
/// use futures_util::future::LocalBoxFuture;
///
2021-01-26 08:05:19 +00:00
/// // use trust-dns async tokio resolver
/// use trust_dns_resolver::TokioAsyncResolver;
///
/// struct MyResolver {
/// trust_dns: TokioAsyncResolver,
/// };
///
/// // impl Resolve trait and convert given host address str and port to SocketAddr.
/// impl Resolve for MyResolver {
/// fn lookup<'a>(
/// &'a self,
/// host: &'a str,
/// port: u16,
/// ) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>> {
/// Box::pin(async move {
/// let res = self
/// .trust_dns
/// .lookup_ip(host)
/// .await?
/// .iter()
/// .map(|ip| SocketAddr::new(ip, port))
/// .collect();
/// Ok(res)
/// })
/// }
/// }
///
/// let resolver = MyResolver {
/// trust_dns: TokioAsyncResolver::tokio_from_system_conf().unwrap(),
/// };
///
/// // construct custom resolver
/// let resolver = Resolver::new_custom(resolver);
///
/// // pass custom resolver to connector builder.
/// // connector would then be usable as a service or awc's connector.
/// let connector = actix_tls::connect::new_connector::<&str>(resolver.clone());
///
/// // resolver can be passed to connector factory where returned service factory
/// // can be used to construct new connector services.
/// let factory = actix_tls::connect::new_connector_factory::<&str>(resolver);
2021-01-26 08:05:19 +00:00
/// ```
pub trait Resolve {
fn lookup<'a>(
&'a self,
host: &'a str,
port: u16,
) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>>;
}
impl Resolver {
/// Constructor for custom Resolve trait object and use it as resolver.
pub fn new_custom(resolver: impl Resolve + 'static) -> Self {
Self::Custom(Rc::new(resolver))
2018-09-10 19:39:55 -07:00
}
2018-09-10 19:16:46 -07:00
// look up with default resolver variant.
fn look_up<T: Address>(req: &Connect<T>) -> JoinHandle<io::Result<IntoIter<SocketAddr>>> {
2021-01-26 08:05:19 +00:00
let host = req.hostname();
// TODO: Connect should always return host with port if possible.
let host = if req
2021-01-26 08:05:19 +00:00
.hostname()
.splitn(2, ':')
.last()
.and_then(|p| p.parse::<u16>().ok())
.map(|p| p == req.port())
.unwrap_or(false)
{
host.to_string()
} else {
format!("{}:{}", host, req.port())
};
2021-01-26 08:05:19 +00:00
// run blocking DNS lookup in thread pool
spawn_blocking(move || std::net::ToSocketAddrs::to_socket_addrs(&host))
2018-09-10 19:16:46 -07:00
}
}
impl<T: Address> Service<Connect<T>> for Resolver {
2019-03-13 15:37:12 -07:00
type Response = Connect<T>;
2019-03-13 12:40:11 -07:00
type Error = ConnectError;
type Future = ResolverFuture<T>;
2018-09-10 19:16:46 -07:00
2020-12-27 14:15:42 +00:00
actix_service::always_ready!();
2018-09-10 19:16:46 -07:00
fn call(&self, req: Connect<T>) -> Self::Future {
2021-01-26 08:05:19 +00:00
if req.addr.is_some() {
ResolverFuture::Connected(Some(req))
2021-01-26 08:05:19 +00:00
} else if let Ok(ip) = req.hostname().parse() {
let addr = SocketAddr::new(ip, req.port());
let req = req.set_addr(Some(addr));
ResolverFuture::Connected(Some(req))
2019-03-13 15:37:12 -07:00
} else {
2021-01-26 08:05:19 +00:00
trace!("DNS resolver: resolving host {:?}", req.hostname());
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
2021-01-26 08:05:19 +00:00
.lookup(req.hostname(), req.port())
.await
.map_err(ConnectError::Resolver)?;
let req = req.set_addrs(addrs);
if req.addr.is_none() {
Err(ConnectError::NoRecords)
} else {
Ok(req)
}
}))
}
}
2018-09-10 19:16:46 -07:00
}
}
}
pub enum ResolverFuture<T: Address> {
Connected(Option<Connect<T>>),
LookUp(
JoinHandle<io::Result<IntoIter<SocketAddr>>>,
Option<Connect<T>>,
),
LookupCustom(LocalBoxFuture<'static, Result<Connect<T>, ConnectError>>),
}
2019-03-13 15:37:12 -07:00
impl<T: Address> Future for ResolverFuture<T> {
Migrate actix-net to std::future (#64) * Migrate actix-codec, actix-rt, and actix-threadpool to std::future * update to latest tokio alpha and futures-rs * Migrate actix-service to std::future, This is a squash of ~8 commits, since it included a lot of experimentation. To see the commits, look into the semtexzv/std-future-service-tmp branch. * update futures-rs and tokio * Migrate actix-threadpool to std::future (#59) * Migrate actix-threadpool to std::future * Cosmetic refactor - turn log::error! into log::warn! as it doesn't throw any error - add Clone and Copy impls for Cancelled making it cheap to operate with - apply rustfmt * Bump up crate version to 0.2.0 and pre-fill its changelog * Disable patching 'actix-threadpool' crate in global workspace as unnecessary * Revert patching and fix 'actix-rt' * Migrate actix-rt to std::future (#47) * remove Pin from Service::poll_ready(); simplify combinators api; make code compile * disable tests * update travis config * refactor naming * drop IntoFuture trait * Migrate actix-server to std::future (#50) Still not finished, this is more WIP, this is an aggregation of several commits, which can be found in semtexzv/std-future-server-tmp branch * update actix-server * rename Factor to ServiceFactory * start server worker in start mehtod * update actix-utils * remove IntoTransform trait * Migrate actix-server::ssl::nativetls to std futures (#61) * Refactor 'nativetls' module * Migrate 'actix-server-config' to std futures - remove "uds" feature - disable features by default * Switch NativeTlsAcceptor to use 'tokio-tls' crate * Bikeshed features names and remove unnecessary dependencies for 'actix-server-config' crate * update openssl impl * migrate actix-connect to std::future * migrate actix-ioframe to std::future * update version to alpha.1 * fix boxed service * migrate server rustls support * migratte openssl and rustls connecttors * store the thread's handle with arbiter (#62) * update ssl connect tests * restore service tests * update readme
2019-11-14 18:38:24 +06:00
type Output = Result<Connect<T>, ConnectError>;
2018-09-10 19:16:46 -07:00
2019-12-02 22:30:09 +06:00
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.get_mut() {
Self::Connected(conn) => Poll::Ready(Ok(conn
.take()
.expect("ResolverFuture polled after finished"))),
2021-01-26 08:05:19 +00:00
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();
2021-01-26 08:05:19 +00:00
let addrs = res.map_err(|err| {
trace!(
"DNS resolver: failed to resolve host {:?} err: {:?}",
2021-01-26 08:05:19 +00:00
req.hostname(),
err
);
2021-01-26 08:05:19 +00:00
err
})?;
2019-07-17 02:17:51 +02:00
let req = req.set_addrs(addrs);
2019-07-17 02:17:51 +02:00
2019-03-13 15:37:12 -07:00
trace!(
"DNS resolver: host {:?} resolved to {:?}",
2021-01-26 08:05:19 +00:00
req.hostname(),
2019-07-17 02:17:51 +02:00
req.addrs()
2019-03-13 15:37:12 -07:00
);
2019-07-17 02:17:51 +02:00
if req.addr.is_none() {
Migrate actix-net to std::future (#64) * Migrate actix-codec, actix-rt, and actix-threadpool to std::future * update to latest tokio alpha and futures-rs * Migrate actix-service to std::future, This is a squash of ~8 commits, since it included a lot of experimentation. To see the commits, look into the semtexzv/std-future-service-tmp branch. * update futures-rs and tokio * Migrate actix-threadpool to std::future (#59) * Migrate actix-threadpool to std::future * Cosmetic refactor - turn log::error! into log::warn! as it doesn't throw any error - add Clone and Copy impls for Cancelled making it cheap to operate with - apply rustfmt * Bump up crate version to 0.2.0 and pre-fill its changelog * Disable patching 'actix-threadpool' crate in global workspace as unnecessary * Revert patching and fix 'actix-rt' * Migrate actix-rt to std::future (#47) * remove Pin from Service::poll_ready(); simplify combinators api; make code compile * disable tests * update travis config * refactor naming * drop IntoFuture trait * Migrate actix-server to std::future (#50) Still not finished, this is more WIP, this is an aggregation of several commits, which can be found in semtexzv/std-future-server-tmp branch * update actix-server * rename Factor to ServiceFactory * start server worker in start mehtod * update actix-utils * remove IntoTransform trait * Migrate actix-server::ssl::nativetls to std futures (#61) * Refactor 'nativetls' module * Migrate 'actix-server-config' to std futures - remove "uds" feature - disable features by default * Switch NativeTlsAcceptor to use 'tokio-tls' crate * Bikeshed features names and remove unnecessary dependencies for 'actix-server-config' crate * update openssl impl * migrate actix-connect to std::future * migrate actix-ioframe to std::future * update version to alpha.1 * fix boxed service * migrate server rustls support * migratte openssl and rustls connecttors * store the thread's handle with arbiter (#62) * update ssl connect tests * restore service tests * update readme
2019-11-14 18:38:24 +06:00
Poll::Ready(Err(ConnectError::NoRecords))
2019-03-13 12:40:11 -07:00
} else {
Migrate actix-net to std::future (#64) * Migrate actix-codec, actix-rt, and actix-threadpool to std::future * update to latest tokio alpha and futures-rs * Migrate actix-service to std::future, This is a squash of ~8 commits, since it included a lot of experimentation. To see the commits, look into the semtexzv/std-future-service-tmp branch. * update futures-rs and tokio * Migrate actix-threadpool to std::future (#59) * Migrate actix-threadpool to std::future * Cosmetic refactor - turn log::error! into log::warn! as it doesn't throw any error - add Clone and Copy impls for Cancelled making it cheap to operate with - apply rustfmt * Bump up crate version to 0.2.0 and pre-fill its changelog * Disable patching 'actix-threadpool' crate in global workspace as unnecessary * Revert patching and fix 'actix-rt' * Migrate actix-rt to std::future (#47) * remove Pin from Service::poll_ready(); simplify combinators api; make code compile * disable tests * update travis config * refactor naming * drop IntoFuture trait * Migrate actix-server to std::future (#50) Still not finished, this is more WIP, this is an aggregation of several commits, which can be found in semtexzv/std-future-server-tmp branch * update actix-server * rename Factor to ServiceFactory * start server worker in start mehtod * update actix-utils * remove IntoTransform trait * Migrate actix-server::ssl::nativetls to std futures (#61) * Refactor 'nativetls' module * Migrate 'actix-server-config' to std futures - remove "uds" feature - disable features by default * Switch NativeTlsAcceptor to use 'tokio-tls' crate * Bikeshed features names and remove unnecessary dependencies for 'actix-server-config' crate * update openssl impl * migrate actix-connect to std::future * migrate actix-ioframe to std::future * update version to alpha.1 * fix boxed service * migrate server rustls support * migratte openssl and rustls connecttors * store the thread's handle with arbiter (#62) * update ssl connect tests * restore service tests * update readme
2019-11-14 18:38:24 +06:00
Poll::Ready(Ok(req))
2019-03-13 12:40:11 -07:00
}
2018-09-10 19:16:46 -07:00
}
2021-01-26 08:05:19 +00:00
Self::LookupCustom(fut) => fut.as_mut().poll(cx),
2018-09-10 19:16:46 -07:00
}
}
}