use std::io; use std::marker::PhantomData; use std::sync::Arc; use actix_service::{NewService, Service}; use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use rustls::{ServerConfig, ServerSession}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_rustls::{Accept, TlsAcceptor, TlsStream}; use crate::counter::{Counter, CounterGuard}; use crate::ssl::MAX_CONN_COUNTER; use crate::{Io, Protocol, ServerConfig as SrvConfig}; use std::pin::Pin; use std::task::Context; /// Support `SSL` connections via rustls package /// /// `rust-tls` feature enables `RustlsAcceptor` type pub struct RustlsAcceptor { config: Arc, io: PhantomData<(T, P)>, } impl RustlsAcceptor { /// Create `RustlsAcceptor` new service pub fn new(config: ServerConfig) -> Self { RustlsAcceptor { config: Arc::new(config), io: PhantomData, } } } impl Clone for RustlsAcceptor { fn clone(&self) -> Self { Self { config: self.config.clone(), io: PhantomData, } } } impl NewService for RustlsAcceptor { type Request = Io; type Response = Io, P>; type Error = io::Error; type Config = SrvConfig; type Service = RustlsAcceptorService; type InitError = (); type Future = FutureResult; fn new_service(&self, cfg: &SrvConfig) -> Self::Future { cfg.set_secure(); MAX_CONN_COUNTER.with(|conns| { ok(RustlsAcceptorService { acceptor: self.config.clone().into(), conns: conns.clone(), io: PhantomData, }) }) } } pub struct RustlsAcceptorService { acceptor: TlsAcceptor, io: PhantomData<(T, P)>, conns: Counter, } impl Service for RustlsAcceptorService { type Request = Io; type Response = Io, P>; type Error = io::Error; type Future = RustlsAcceptorServiceFut; fn poll_ready( self: Pin<&mut Self>, ctx: &mut Context<'_>, ) -> Poll> { if self.conns.available(cx) { Ok(Async::Ready(())) } else { Ok(Async::NotReady) } } fn call(&mut self, req: Self::Request) -> Self::Future { let (io, params, _) = req.into_parts(); RustlsAcceptorServiceFut { _guard: self.conns.get(), fut: self.acceptor.accept(io), params: Some(params), } } } pub struct RustlsAcceptorServiceFut where T: AsyncRead + AsyncWrite, { fut: Accept, params: Option

, _guard: CounterGuard, } impl Future for RustlsAcceptorServiceFut { type Item = Io, P>; type Error = io::Error; fn poll(&mut self) -> Poll { let io = futures::try_ready!(self.fut.poll()); Ok(Async::Ready(Io::from_parts( io, self.params.take().unwrap(), Protocol::Unknown, ))) } }