mirror of
https://github.com/fafhrd91/actix-net
synced 2025-06-28 20:10:35 +02:00
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
This commit is contained in:
@ -1,11 +1,15 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_service::{NewService, Service};
|
||||
use futures::future::{err, ok, Either, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
use tokio_tcp::{ConnectFuture, TcpStream};
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use futures::future::{err, ok, BoxFuture, Either, FutureExt, Ready};
|
||||
use pin_project::pin_project;
|
||||
use tokio_net::tcp::TcpStream;
|
||||
|
||||
use super::connect::{Address, Connect, Connection};
|
||||
use super::error::ConnectError;
|
||||
@ -37,14 +41,14 @@ impl<T> Clone for TcpConnectorFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address> NewService for TcpConnectorFactory<T> {
|
||||
impl<T: Address> ServiceFactory for TcpConnectorFactory<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Config = ();
|
||||
type Service = TcpConnector<T>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(self.service())
|
||||
@ -71,10 +75,10 @@ impl<T: Address> Service for TcpConnector<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Future = Either<TcpConnectorResponse<T>, FutureResult<Self::Response, Self::Error>>;
|
||||
type Future = Either<TcpConnectorResponse<T>, Ready<Result<Self::Response, Self::Error>>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||
@ -82,21 +86,22 @@ impl<T: Address> Service for TcpConnector<T> {
|
||||
let Connect { req, addr, .. } = req;
|
||||
|
||||
if let Some(addr) = addr {
|
||||
Either::A(TcpConnectorResponse::new(req, port, addr))
|
||||
Either::Left(TcpConnectorResponse::new(req, port, addr))
|
||||
} else {
|
||||
error!("TCP connector: got unresolved address");
|
||||
Either::B(err(ConnectError::Unresolverd))
|
||||
Either::Right(err(ConnectError::Unresolverd))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
#[doc(hidden)]
|
||||
/// Tcp stream connector response future
|
||||
pub struct TcpConnectorResponse<T> {
|
||||
req: Option<T>,
|
||||
port: u16,
|
||||
addrs: Option<VecDeque<SocketAddr>>,
|
||||
stream: Option<ConnectFuture>,
|
||||
stream: Option<BoxFuture<'static, Result<TcpStream, io::Error>>>,
|
||||
}
|
||||
|
||||
impl<T: Address> TcpConnectorResponse<T> {
|
||||
@ -116,7 +121,7 @@ impl<T: Address> TcpConnectorResponse<T> {
|
||||
req: Some(req),
|
||||
port,
|
||||
addrs: None,
|
||||
stream: Some(TcpStream::connect(&addr)),
|
||||
stream: Some(TcpStream::connect(addr).boxed()),
|
||||
},
|
||||
either::Either::Right(addrs) => TcpConnectorResponse {
|
||||
req: Some(req),
|
||||
@ -129,40 +134,40 @@ impl<T: Address> TcpConnectorResponse<T> {
|
||||
}
|
||||
|
||||
impl<T: Address> Future for TcpConnectorResponse<T> {
|
||||
type Item = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Output = Result<Connection<T, TcpStream>, ConnectError>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
// connect
|
||||
loop {
|
||||
if let Some(new) = self.stream.as_mut() {
|
||||
match new.poll() {
|
||||
Ok(Async::Ready(sock)) => {
|
||||
let req = self.req.take().unwrap();
|
||||
if let Some(new) = this.stream.as_mut() {
|
||||
match new.as_mut().poll(cx) {
|
||||
Poll::Ready(Ok(sock)) => {
|
||||
let req = this.req.take().unwrap();
|
||||
trace!(
|
||||
"TCP connector - successfully connected to connecting to {:?} - {:?}",
|
||||
req.host(), sock.peer_addr()
|
||||
);
|
||||
return Ok(Async::Ready(Connection::new(sock, req)));
|
||||
return Poll::Ready(Ok(Connection::new(sock, req)));
|
||||
}
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Err(err) => {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(Err(err)) => {
|
||||
trace!(
|
||||
"TCP connector - failed to connect to connecting to {:?} port: {}",
|
||||
self.req.as_ref().unwrap().host(),
|
||||
self.port,
|
||||
this.req.as_ref().unwrap().host(),
|
||||
this.port,
|
||||
);
|
||||
if self.addrs.is_none() || self.addrs.as_ref().unwrap().is_empty() {
|
||||
return Err(err.into());
|
||||
if this.addrs.is_none() || this.addrs.as_ref().unwrap().is_empty() {
|
||||
return Poll::Ready(Err(err.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// try to connect
|
||||
self.stream = Some(TcpStream::connect(
|
||||
&self.addrs.as_mut().unwrap().pop_front().unwrap(),
|
||||
));
|
||||
let addr = this.addrs.as_mut().unwrap().pop_front().unwrap();
|
||||
*this.stream = Some(TcpStream::connect(addr).boxed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ pub use self::resolver::{Resolver, ResolverFactory};
|
||||
pub use self::service::{ConnectService, ConnectServiceFactory, TcpConnectService};
|
||||
|
||||
use actix_rt::Arbiter;
|
||||
use actix_service::{NewService, Service, ServiceExt};
|
||||
use tokio_tcp::TcpStream;
|
||||
use actix_service::{pipeline, pipeline_factory, Service, ServiceFactory};
|
||||
use tokio_net::tcp::TcpStream;
|
||||
|
||||
pub fn start_resolver(cfg: ResolverConfig, opts: ResolverOpts) -> AsyncResolver {
|
||||
let (resolver, bg) = AsyncResolver::new(cfg, opts);
|
||||
tokio_current_thread::spawn(bg);
|
||||
tokio_executor::current_thread::spawn(bg);
|
||||
resolver
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ pub(crate) fn get_default_resolver() -> AsyncResolver {
|
||||
};
|
||||
|
||||
let (resolver, bg) = AsyncResolver::new(cfg, opts);
|
||||
tokio_current_thread::spawn(bg);
|
||||
tokio_executor::current_thread::spawn(bg);
|
||||
|
||||
Arbiter::set_item(DefaultResolver(resolver.clone()));
|
||||
resolver
|
||||
@ -70,37 +70,37 @@ pub fn start_default_resolver() -> AsyncResolver {
|
||||
pub fn new_connector<T: Address>(
|
||||
resolver: AsyncResolver,
|
||||
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
||||
+ Clone {
|
||||
Resolver::new(resolver).and_then(TcpConnector::new())
|
||||
{
|
||||
pipeline(Resolver::new(resolver)).and_then(TcpConnector::new())
|
||||
}
|
||||
|
||||
/// Create tcp connector service
|
||||
pub fn new_connector_factory<T: Address>(
|
||||
resolver: AsyncResolver,
|
||||
) -> impl NewService<
|
||||
) -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = Connect<T>,
|
||||
Response = Connection<T, TcpStream>,
|
||||
Error = ConnectError,
|
||||
InitError = (),
|
||||
> + Clone {
|
||||
ResolverFactory::new(resolver).and_then(TcpConnectorFactory::new())
|
||||
> {
|
||||
pipeline_factory(ResolverFactory::new(resolver)).and_then(TcpConnectorFactory::new())
|
||||
}
|
||||
|
||||
/// Create connector service with default parameters
|
||||
pub fn default_connector<T: Address>(
|
||||
) -> impl Service<Request = Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError>
|
||||
+ Clone {
|
||||
Resolver::default().and_then(TcpConnector::new())
|
||||
{
|
||||
pipeline(Resolver::default()).and_then(TcpConnector::new())
|
||||
}
|
||||
|
||||
/// Create connector service factory with default parameters
|
||||
pub fn default_connector_factory<T: Address>() -> impl NewService<
|
||||
pub fn default_connector_factory<T: Address>() -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = Connect<T>,
|
||||
Response = Connection<T, TcpStream>,
|
||||
Error = ConnectError,
|
||||
InitError = (),
|
||||
> + Clone {
|
||||
ResolverFactory::default().and_then(TcpConnectorFactory::new())
|
||||
> {
|
||||
pipeline_factory(ResolverFactory::default()).and_then(TcpConnectorFactory::new())
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_service::{NewService, Service};
|
||||
use futures::future::{ok, Either, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use futures::future::{ok, Either, Ready};
|
||||
use pin_project::pin_project;
|
||||
use trust_dns_resolver::lookup_ip::LookupIpFuture;
|
||||
use trust_dns_resolver::{AsyncResolver, Background};
|
||||
|
||||
@ -52,14 +55,14 @@ impl<T> Clone for ResolverFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address> NewService for ResolverFactory<T> {
|
||||
impl<T: Address> ServiceFactory for ResolverFactory<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connect<T>;
|
||||
type Error = ConnectError;
|
||||
type Config = ();
|
||||
type Service = Resolver<T>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(self.service())
|
||||
@ -104,32 +107,34 @@ impl<T: Address> Service for Resolver<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connect<T>;
|
||||
type Error = ConnectError;
|
||||
type Future = Either<ResolverFuture<T>, FutureResult<Connect<T>, Self::Error>>;
|
||||
type Future = Either<ResolverFuture<T>, Ready<Result<Connect<T>, Self::Error>>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, mut req: Connect<T>) -> Self::Future {
|
||||
if req.addr.is_some() {
|
||||
Either::B(ok(req))
|
||||
Either::Right(ok(req))
|
||||
} else if let Ok(ip) = req.host().parse() {
|
||||
req.addr = Some(either::Either::Left(SocketAddr::new(ip, req.port())));
|
||||
Either::B(ok(req))
|
||||
Either::Right(ok(req))
|
||||
} else {
|
||||
trace!("DNS resolver: resolving host {:?}", req.host());
|
||||
if self.resolver.is_none() {
|
||||
self.resolver = Some(get_default_resolver());
|
||||
}
|
||||
Either::A(ResolverFuture::new(req, self.resolver.as_ref().unwrap()))
|
||||
Either::Left(ResolverFuture::new(req, self.resolver.as_ref().unwrap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
#[doc(hidden)]
|
||||
/// Resolver future
|
||||
pub struct ResolverFuture<T: Address> {
|
||||
req: Option<Connect<T>>,
|
||||
#[pin]
|
||||
lookup: Background<LookupIpFuture>,
|
||||
}
|
||||
|
||||
@ -149,22 +154,15 @@ impl<T: Address> ResolverFuture<T> {
|
||||
}
|
||||
|
||||
impl<T: Address> Future for ResolverFuture<T> {
|
||||
type Item = Connect<T>;
|
||||
type Error = ConnectError;
|
||||
type Output = Result<Connect<T>, ConnectError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.lookup.poll().map_err(|e| {
|
||||
trace!(
|
||||
"DNS resolver: failed to resolve host {:?} err: {}",
|
||||
self.req.as_ref().unwrap().host(),
|
||||
e
|
||||
);
|
||||
e
|
||||
})? {
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
Async::Ready(ips) => {
|
||||
let req = self.req.take().unwrap();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
|
||||
match this.lookup.poll(cx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Ok(ips)) => {
|
||||
let req = this.req.take().unwrap();
|
||||
let port = req.port();
|
||||
let req = req.set_addrs(ips.iter().map(|ip| SocketAddr::new(ip, port)));
|
||||
|
||||
@ -175,11 +173,19 @@ impl<T: Address> Future for ResolverFuture<T> {
|
||||
);
|
||||
|
||||
if req.addr.is_none() {
|
||||
Err(ConnectError::NoRecords)
|
||||
Poll::Ready(Err(ConnectError::NoRecords))
|
||||
} else {
|
||||
Ok(Async::Ready(req))
|
||||
Poll::Ready(Ok(req))
|
||||
}
|
||||
}
|
||||
Poll::Ready(Err(e)) => {
|
||||
trace!(
|
||||
"DNS resolver: failed to resolve host {:?} err: {}",
|
||||
this.req.as_ref().unwrap().host(),
|
||||
e
|
||||
);
|
||||
Poll::Ready(Err(e.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
use actix_service::{NewService, Service};
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{try_ready, Async, Future, Poll};
|
||||
use tokio_tcp::TcpStream;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use either::Either;
|
||||
use futures::future::{ok, Ready};
|
||||
use tokio_net::tcp::TcpStream;
|
||||
use trust_dns_resolver::AsyncResolver;
|
||||
|
||||
use crate::connect::{Address, Connect, Connection};
|
||||
@ -14,7 +18,7 @@ pub struct ConnectServiceFactory<T> {
|
||||
resolver: ResolverFactory<T>,
|
||||
}
|
||||
|
||||
impl<T> ConnectServiceFactory<T> {
|
||||
impl<T: Unpin> ConnectServiceFactory<T> {
|
||||
/// Construct new ConnectService factory
|
||||
pub fn new() -> Self {
|
||||
ConnectServiceFactory {
|
||||
@ -66,14 +70,14 @@ impl<T> Clone for ConnectServiceFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address> NewService for ConnectServiceFactory<T> {
|
||||
impl<T: Address + Unpin> ServiceFactory for ConnectServiceFactory<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Config = ();
|
||||
type Service = ConnectService<T>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(self.service())
|
||||
@ -86,47 +90,66 @@ pub struct ConnectService<T> {
|
||||
resolver: Resolver<T>,
|
||||
}
|
||||
|
||||
impl<T: Address> Service for ConnectService<T> {
|
||||
impl<T: Address + Unpin> Service for ConnectService<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Future = ConnectServiceResponse<T>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||
ConnectServiceResponse {
|
||||
fut1: Some(self.resolver.call(req)),
|
||||
fut2: None,
|
||||
state: ConnectState::Resolve(self.resolver.call(req)),
|
||||
tcp: self.tcp.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConnectServiceResponse<T: Address> {
|
||||
fut1: Option<<Resolver<T> as Service>::Future>,
|
||||
fut2: Option<<TcpConnector<T> as Service>::Future>,
|
||||
enum ConnectState<T: Address + Unpin> {
|
||||
Resolve(<Resolver<T> as Service>::Future),
|
||||
Connect(<TcpConnector<T> as Service>::Future),
|
||||
}
|
||||
|
||||
impl<T: Address + Unpin> ConnectState<T> {
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
) -> Either<Poll<Result<Connection<T, TcpStream>, ConnectError>>, Connect<T>> {
|
||||
match self {
|
||||
ConnectState::Resolve(ref mut fut) => match Pin::new(fut).poll(cx) {
|
||||
Poll::Pending => Either::Left(Poll::Pending),
|
||||
Poll::Ready(Ok(res)) => Either::Right(res),
|
||||
Poll::Ready(Err(err)) => Either::Left(Poll::Ready(Err(err))),
|
||||
},
|
||||
ConnectState::Connect(ref mut fut) => Either::Left(Pin::new(fut).poll(cx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConnectServiceResponse<T: Address + Unpin> {
|
||||
state: ConnectState<T>,
|
||||
tcp: TcpConnector<T>,
|
||||
}
|
||||
|
||||
impl<T: Address> Future for ConnectServiceResponse<T> {
|
||||
type Item = Connection<T, TcpStream>;
|
||||
type Error = ConnectError;
|
||||
impl<T: Address + Unpin> Future for ConnectServiceResponse<T> {
|
||||
type Output = Result<Connection<T, TcpStream>, ConnectError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(ref mut fut) = self.fut1 {
|
||||
let res = try_ready!(fut.poll());
|
||||
let _ = self.fut1.take();
|
||||
self.fut2 = Some(self.tcp.call(res));
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let res = match self.state.poll(cx) {
|
||||
Either::Right(res) => {
|
||||
self.state = ConnectState::Connect(self.tcp.call(res));
|
||||
self.state.poll(cx)
|
||||
}
|
||||
Either::Left(res) => return res,
|
||||
};
|
||||
|
||||
match res {
|
||||
Either::Left(res) => res,
|
||||
Either::Right(_) => panic!(),
|
||||
}
|
||||
|
||||
if let Some(ref mut fut) = self.fut2 {
|
||||
return fut.poll();
|
||||
}
|
||||
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,48 +159,73 @@ pub struct TcpConnectService<T> {
|
||||
resolver: Resolver<T>,
|
||||
}
|
||||
|
||||
impl<T: Address> Service for TcpConnectService<T> {
|
||||
impl<T: Address + Unpin + 'static> Service for TcpConnectService<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = TcpStream;
|
||||
type Error = ConnectError;
|
||||
type Future = TcpConnectServiceResponse<T>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||
TcpConnectServiceResponse {
|
||||
fut1: Some(self.resolver.call(req)),
|
||||
fut2: None,
|
||||
state: TcpConnectState::Resolve(self.resolver.call(req)),
|
||||
tcp: self.tcp.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpConnectServiceResponse<T: Address> {
|
||||
fut1: Option<<Resolver<T> as Service>::Future>,
|
||||
fut2: Option<<TcpConnector<T> as Service>::Future>,
|
||||
enum TcpConnectState<T: Address + Unpin> {
|
||||
Resolve(<Resolver<T> as Service>::Future),
|
||||
Connect(<TcpConnector<T> as Service>::Future),
|
||||
}
|
||||
|
||||
impl<T: Address + Unpin> TcpConnectState<T> {
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context,
|
||||
) -> Either<Poll<Result<TcpStream, ConnectError>>, Connect<T>> {
|
||||
match self {
|
||||
TcpConnectState::Resolve(ref mut fut) => match Pin::new(fut).poll(cx) {
|
||||
Poll::Pending => (),
|
||||
Poll::Ready(Ok(res)) => return Either::Right(res),
|
||||
Poll::Ready(Err(err)) => return Either::Left(Poll::Ready(Err(err))),
|
||||
},
|
||||
TcpConnectState::Connect(ref mut fut) => {
|
||||
if let Poll::Ready(res) = Pin::new(fut).poll(cx) {
|
||||
return match res {
|
||||
Ok(conn) => Either::Left(Poll::Ready(Ok(conn.into_parts().0))),
|
||||
Err(err) => Either::Left(Poll::Ready(Err(err))),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Either::Left(Poll::Pending)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpConnectServiceResponse<T: Address + Unpin> {
|
||||
state: TcpConnectState<T>,
|
||||
tcp: TcpConnector<T>,
|
||||
}
|
||||
|
||||
impl<T: Address> Future for TcpConnectServiceResponse<T> {
|
||||
type Item = TcpStream;
|
||||
type Error = ConnectError;
|
||||
impl<T: Address + Unpin> Future for TcpConnectServiceResponse<T> {
|
||||
type Output = Result<TcpStream, ConnectError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(ref mut fut) = self.fut1 {
|
||||
let res = try_ready!(fut.poll());
|
||||
let _ = self.fut1.take();
|
||||
self.fut2 = Some(self.tcp.call(res));
|
||||
}
|
||||
|
||||
if let Some(ref mut fut) = self.fut2 {
|
||||
if let Async::Ready(conn) = fut.poll()? {
|
||||
return Ok(Async::Ready(conn.into_parts().0));
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let res = match self.state.poll(cx) {
|
||||
Either::Right(res) => {
|
||||
self.state = TcpConnectState::Connect(self.tcp.call(res));
|
||||
self.state.poll(cx)
|
||||
}
|
||||
}
|
||||
Either::Left(res) => return res,
|
||||
};
|
||||
|
||||
Ok(Async::NotReady)
|
||||
match res {
|
||||
Either::Left(res) => res,
|
||||
Either::Right(_) => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,13 @@
|
||||
//! SSL Services
|
||||
|
||||
#[cfg(feature = "ssl")]
|
||||
#[cfg(feature = "openssl")]
|
||||
mod openssl;
|
||||
#[cfg(feature = "ssl")]
|
||||
#[cfg(feature = "openssl")]
|
||||
pub use self::openssl::{
|
||||
OpensslConnectService, OpensslConnectServiceFactory, OpensslConnector,
|
||||
};
|
||||
#[cfg(feature = "rust-tls")]
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
mod rustls;
|
||||
#[cfg(feature = "rust-tls")]
|
||||
#[cfg(feature = "rustls")]
|
||||
pub use self::rustls::RustlsConnector;
|
||||
|
@ -1,12 +1,15 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{fmt, io};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_service::{NewService, Service};
|
||||
use futures::{future::ok, future::FutureResult, try_ready, Async, Future, Poll};
|
||||
use openssl::ssl::{HandshakeError, SslConnector};
|
||||
use tokio_openssl::{ConnectAsync, SslConnectorExt, SslStream};
|
||||
use tokio_tcp::TcpStream;
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use futures::future::{err, ok, Either, FutureExt, LocalBoxFuture, Ready};
|
||||
use open_ssl::ssl::SslConnector;
|
||||
use tokio_net::tcp::TcpStream;
|
||||
use tokio_openssl::{HandshakeError, SslStream};
|
||||
use trust_dns_resolver::AsyncResolver;
|
||||
|
||||
use crate::{
|
||||
@ -30,15 +33,15 @@ impl<T, U> OpensslConnector<T, U> {
|
||||
|
||||
impl<T, U> OpensslConnector<T, U>
|
||||
where
|
||||
T: Address,
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
T: Address + Unpin + 'static,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
|
||||
{
|
||||
pub fn service(
|
||||
connector: SslConnector,
|
||||
) -> impl Service<
|
||||
Request = Connection<T, U>,
|
||||
Response = Connection<T, SslStream<U>>,
|
||||
Error = HandshakeError<U>,
|
||||
Error = io::Error,
|
||||
> {
|
||||
OpensslConnectorService {
|
||||
connector: connector,
|
||||
@ -56,17 +59,17 @@ impl<T, U> Clone for OpensslConnector<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address, U> NewService for OpensslConnector<T, U>
|
||||
impl<T: Address + Unpin + 'static, U> ServiceFactory for OpensslConnector<T, U>
|
||||
where
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
|
||||
{
|
||||
type Request = Connection<T, U>;
|
||||
type Response = Connection<T, SslStream<U>>;
|
||||
type Error = HandshakeError<U>;
|
||||
type Error = io::Error;
|
||||
type Config = ();
|
||||
type Service = OpensslConnectorService<T, U>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(OpensslConnectorService {
|
||||
@ -90,52 +93,62 @@ impl<T, U> Clone for OpensslConnectorService<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address, U> Service for OpensslConnectorService<T, U>
|
||||
impl<T: Address + Unpin + 'static, U> Service for OpensslConnectorService<T, U>
|
||||
where
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
|
||||
{
|
||||
type Request = Connection<T, U>;
|
||||
type Response = Connection<T, SslStream<U>>;
|
||||
type Error = HandshakeError<U>;
|
||||
type Future = ConnectAsyncExt<T, U>;
|
||||
type Error = io::Error;
|
||||
type Future = Either<ConnectAsyncExt<T, U>, Ready<Result<Self::Response, Self::Error>>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, stream: Connection<T, U>) -> Self::Future {
|
||||
trace!("SSL Handshake start for: {:?}", stream.host());
|
||||
let (io, stream) = stream.replace(());
|
||||
ConnectAsyncExt {
|
||||
fut: SslConnectorExt::connect_async(&self.connector, stream.host(), io),
|
||||
stream: Some(stream),
|
||||
let host = stream.host().to_string();
|
||||
|
||||
match self.connector.configure() {
|
||||
Err(e) => Either::Right(err(io::Error::new(io::ErrorKind::Other, e))),
|
||||
Ok(config) => Either::Left(ConnectAsyncExt {
|
||||
fut: async move { tokio_openssl::connect(config, &host, io).await }
|
||||
.boxed_local(),
|
||||
stream: Some(stream),
|
||||
_t: PhantomData,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConnectAsyncExt<T, U> {
|
||||
fut: ConnectAsync<U>,
|
||||
fut: LocalBoxFuture<'static, Result<SslStream<U>, HandshakeError<U>>>,
|
||||
stream: Option<Connection<T, ()>>,
|
||||
_t: PhantomData<U>,
|
||||
}
|
||||
|
||||
impl<T: Address, U> Future for ConnectAsyncExt<T, U>
|
||||
impl<T: Address + Unpin, U> Future for ConnectAsyncExt<T, U>
|
||||
where
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
|
||||
{
|
||||
type Item = Connection<T, SslStream<U>>;
|
||||
type Error = HandshakeError<U>;
|
||||
type Output = Result<Connection<T, SslStream<U>>, io::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.fut.poll().map_err(|e| {
|
||||
trace!("SSL Handshake error: {:?}", e);
|
||||
e
|
||||
})? {
|
||||
Async::Ready(stream) => {
|
||||
let s = self.stream.take().unwrap();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
|
||||
match Pin::new(&mut this.fut).poll(cx) {
|
||||
Poll::Ready(Ok(stream)) => {
|
||||
let s = this.stream.take().unwrap();
|
||||
trace!("SSL Handshake success: {:?}", s.host());
|
||||
Ok(Async::Ready(s.replace(stream).1))
|
||||
Poll::Ready(Ok(s.replace(stream).1))
|
||||
}
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
Poll::Ready(Err(e)) => {
|
||||
trace!("SSL Handshake error: {:?}", e);
|
||||
Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
|
||||
}
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,7 +158,7 @@ pub struct OpensslConnectServiceFactory<T> {
|
||||
openssl: OpensslConnector<T, TcpStream>,
|
||||
}
|
||||
|
||||
impl<T> OpensslConnectServiceFactory<T> {
|
||||
impl<T: Unpin> OpensslConnectServiceFactory<T> {
|
||||
/// Construct new OpensslConnectService factory
|
||||
pub fn new(connector: SslConnector) -> Self {
|
||||
OpensslConnectServiceFactory {
|
||||
@ -183,14 +196,14 @@ impl<T> Clone for OpensslConnectServiceFactory<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address> NewService for OpensslConnectServiceFactory<T> {
|
||||
impl<T: Address + Unpin + 'static> ServiceFactory for OpensslConnectServiceFactory<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = SslStream<TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Config = ();
|
||||
type Service = OpensslConnectService<T>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(self.service())
|
||||
@ -203,14 +216,14 @@ pub struct OpensslConnectService<T> {
|
||||
openssl: OpensslConnectorService<T, TcpStream>,
|
||||
}
|
||||
|
||||
impl<T: Address> Service for OpensslConnectService<T> {
|
||||
impl<T: Address + Unpin + 'static> Service for OpensslConnectService<T> {
|
||||
type Request = Connect<T>;
|
||||
type Response = SslStream<TcpStream>;
|
||||
type Error = ConnectError;
|
||||
type Future = OpensslConnectServiceResponse<T>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||
@ -222,30 +235,36 @@ impl<T: Address> Service for OpensslConnectService<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OpensslConnectServiceResponse<T: Address> {
|
||||
pub struct OpensslConnectServiceResponse<T: Address + Unpin + 'static> {
|
||||
fut1: Option<<ConnectService<T> as Service>::Future>,
|
||||
fut2: Option<<OpensslConnectorService<T, TcpStream> as Service>::Future>,
|
||||
openssl: OpensslConnectorService<T, TcpStream>,
|
||||
}
|
||||
|
||||
impl<T: Address> Future for OpensslConnectServiceResponse<T> {
|
||||
type Item = SslStream<TcpStream>;
|
||||
type Error = ConnectError;
|
||||
impl<T: Address + Unpin> Future for OpensslConnectServiceResponse<T> {
|
||||
type Output = Result<SslStream<TcpStream>, ConnectError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
if let Some(ref mut fut) = self.fut1 {
|
||||
let res = try_ready!(fut.poll());
|
||||
let _ = self.fut1.take();
|
||||
self.fut2 = Some(self.openssl.call(res));
|
||||
match futures::ready!(Pin::new(fut).poll(cx)) {
|
||||
Ok(res) => {
|
||||
let _ = self.fut1.take();
|
||||
self.fut2 = Some(self.openssl.call(res));
|
||||
}
|
||||
Err(e) => return Poll::Ready(Err(e.into())),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut fut) = self.fut2 {
|
||||
let connect = try_ready!(fut
|
||||
.poll()
|
||||
.map_err(|e| ConnectError::Io(io::Error::new(io::ErrorKind::Other, e))));
|
||||
Ok(Async::Ready(connect.into_parts().0))
|
||||
match futures::ready!(Pin::new(fut).poll(cx)) {
|
||||
Ok(connect) => Poll::Ready(Ok(connect.into_parts().0)),
|
||||
Err(e) => Poll::Ready(Err(ConnectError::Io(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
e,
|
||||
)))),
|
||||
}
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use actix_codec::{AsyncRead, AsyncWrite};
|
||||
use actix_service::{NewService, Service};
|
||||
use futures::{future::ok, future::FutureResult, Async, Future, Poll};
|
||||
use std::sync::Arc;
|
||||
use actix_service::{Service, ServiceFactory};
|
||||
use futures::future::{ok, Ready};
|
||||
use tokio_rustls::{client::TlsStream, rustls::ClientConfig, Connect, TlsConnector};
|
||||
use webpki::DNSNameRef;
|
||||
|
||||
@ -27,8 +30,8 @@ impl<T, U> RustlsConnector<T, U> {
|
||||
|
||||
impl<T, U> RustlsConnector<T, U>
|
||||
where
|
||||
T: Address,
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
T: Address + Unpin,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
|
||||
{
|
||||
pub fn service(
|
||||
connector: Arc<ClientConfig>,
|
||||
@ -53,9 +56,9 @@ impl<T, U> Clone for RustlsConnector<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Address, U> NewService for RustlsConnector<T, U>
|
||||
impl<T: Address + Unpin, U> ServiceFactory for RustlsConnector<T, U>
|
||||
where
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
|
||||
{
|
||||
type Request = Connection<T, U>;
|
||||
type Response = Connection<T, TlsStream<U>>;
|
||||
@ -63,7 +66,7 @@ where
|
||||
type Config = ();
|
||||
type Service = RustlsConnectorService<T, U>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(RustlsConnectorService {
|
||||
@ -78,17 +81,17 @@ pub struct RustlsConnectorService<T, U> {
|
||||
_t: PhantomData<(T, U)>,
|
||||
}
|
||||
|
||||
impl<T: Address, U> Service for RustlsConnectorService<T, U>
|
||||
impl<T: Address + Unpin, U> Service for RustlsConnectorService<T, U>
|
||||
where
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
|
||||
{
|
||||
type Request = Connection<T, U>;
|
||||
type Response = Connection<T, TlsStream<U>>;
|
||||
type Error = std::io::Error;
|
||||
type Future = ConnectAsyncExt<T, U>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, stream: Connection<T, U>) -> Self::Future {
|
||||
@ -108,24 +111,20 @@ pub struct ConnectAsyncExt<T, U> {
|
||||
stream: Option<Connection<T, ()>>,
|
||||
}
|
||||
|
||||
impl<T: Address, U> Future for ConnectAsyncExt<T, U>
|
||||
impl<T: Address + Unpin, U> Future for ConnectAsyncExt<T, U>
|
||||
where
|
||||
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
|
||||
{
|
||||
type Item = Connection<T, TlsStream<U>>;
|
||||
type Error = std::io::Error;
|
||||
type Output = Result<Connection<T, TlsStream<U>>, std::io::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.fut.poll().map_err(|e| {
|
||||
trace!("SSL Handshake error: {:?}", e);
|
||||
e
|
||||
})? {
|
||||
Async::Ready(stream) => {
|
||||
let s = self.stream.take().unwrap();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
Poll::Ready(
|
||||
futures::ready!(Pin::new(&mut this.fut).poll(cx)).map(|stream| {
|
||||
let s = this.stream.take().unwrap();
|
||||
trace!("SSL Handshake success: {:?}", s.host());
|
||||
Ok(Async::Ready(s.replace(stream).1))
|
||||
}
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
}
|
||||
s.replace(stream).1
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user