use std::marker::PhantomData; 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 trust_dns_resolver::AsyncResolver; use crate::{ Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection, }; /// Openssl connector factory pub struct OpensslConnector { connector: SslConnector, _t: PhantomData<(T, U)>, } impl OpensslConnector { pub fn new(connector: SslConnector) -> Self { OpensslConnector { connector, _t: PhantomData, } } } impl OpensslConnector where T: Address, U: AsyncRead + AsyncWrite + fmt::Debug, { pub fn service( connector: SslConnector, ) -> impl Service< Request = Connection, Response = Connection>, Error = HandshakeError, > { OpensslConnectorService { connector: connector, _t: PhantomData, } } } impl Clone for OpensslConnector { fn clone(&self) -> Self { Self { connector: self.connector.clone(), _t: PhantomData, } } } impl NewService for OpensslConnector where U: AsyncRead + AsyncWrite + fmt::Debug, { type Request = Connection; type Response = Connection>; type Error = HandshakeError; type Config = (); type Service = OpensslConnectorService; type InitError = (); type Future = FutureResult; fn new_service(&self, _: &()) -> Self::Future { ok(OpensslConnectorService { connector: self.connector.clone(), _t: PhantomData, }) } } pub struct OpensslConnectorService { connector: SslConnector, _t: PhantomData<(T, U)>, } impl Clone for OpensslConnectorService { fn clone(&self) -> Self { Self { connector: self.connector.clone(), _t: PhantomData, } } } impl Service for OpensslConnectorService where U: AsyncRead + AsyncWrite + fmt::Debug, { type Request = Connection; type Response = Connection>; type Error = HandshakeError; type Future = ConnectAsyncExt; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, stream: Connection) -> 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), } } } pub struct ConnectAsyncExt { fut: ConnectAsync, stream: Option>, } impl Future for ConnectAsyncExt where U: AsyncRead + AsyncWrite + fmt::Debug, { type Item = Connection>; type Error = HandshakeError; fn poll(&mut self) -> Poll { match self.fut.poll().map_err(|e| { trace!("SSL Handshake error: {:?}", e); e })? { Async::Ready(stream) => { let s = self.stream.take().unwrap(); trace!("SSL Handshake success: {:?}", s.host()); Ok(Async::Ready(s.replace(stream).1)) } Async::NotReady => Ok(Async::NotReady), } } } pub struct OpensslConnectServiceFactory { tcp: ConnectServiceFactory, openssl: OpensslConnector, } impl OpensslConnectServiceFactory { /// Construct new OpensslConnectService factory pub fn new(connector: SslConnector) -> Self { OpensslConnectServiceFactory { tcp: ConnectServiceFactory::default(), openssl: OpensslConnector::new(connector), } } /// Construct new connect service with custom dns resolver pub fn with_resolver(connector: SslConnector, resolver: AsyncResolver) -> Self { OpensslConnectServiceFactory { tcp: ConnectServiceFactory::with_resolver(resolver), openssl: OpensslConnector::new(connector), } } /// Construct openssl connect service pub fn service(&self) -> OpensslConnectService { OpensslConnectService { tcp: self.tcp.service(), openssl: OpensslConnectorService { connector: self.openssl.connector.clone(), _t: PhantomData, }, } } } impl Clone for OpensslConnectServiceFactory { fn clone(&self) -> Self { OpensslConnectServiceFactory { tcp: self.tcp.clone(), openssl: self.openssl.clone(), } } } impl NewService for OpensslConnectServiceFactory { type Request = Connect; type Response = SslStream; type Error = ConnectError; type Config = (); type Service = OpensslConnectService; type InitError = (); type Future = FutureResult; fn new_service(&self, _: &()) -> Self::Future { ok(self.service()) } } #[derive(Clone)] pub struct OpensslConnectService { tcp: ConnectService, openssl: OpensslConnectorService, } impl Service for OpensslConnectService { type Request = Connect; type Response = SslStream; type Error = ConnectError; type Future = OpensslConnectServiceResponse; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, req: Connect) -> Self::Future { OpensslConnectServiceResponse { fut1: Some(self.tcp.call(req)), fut2: None, openssl: self.openssl.clone(), } } } pub struct OpensslConnectServiceResponse { fut1: Option< as Service>::Future>, fut2: Option< as Service>::Future>, openssl: OpensslConnectorService, } impl Future for OpensslConnectServiceResponse { type Item = SslStream; type Error = ConnectError; fn poll(&mut self) -> Poll { 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)); } 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)) } else { Ok(Async::NotReady) } } }