From cb052679abd33a1ed5ba8d5bef10b72b5edb9ae9 Mon Sep 17 00:00:00 2001 From: tyranron Date: Tue, 12 Nov 2019 22:36:30 +0200 Subject: [PATCH] Switch NativeTlsAcceptor to use 'tokio-tls' crate --- actix-server/Cargo.toml | 13 +- actix-server/src/ssl/mod.rs | 2 +- actix-server/src/ssl/nativetls.rs | 197 +++++++++--------------------- 3 files changed, 64 insertions(+), 148 deletions(-) diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index ca9d0a6e..3e9355f5 100644 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -23,8 +23,8 @@ path = "src/lib.rs" [features] default = [] -# tls -tls = ["native-tls"] +# native-tls +tls = ["native-tls", "tokio-tls"] # openssl ssl = ["openssl", "tokio-openssl", "actix-server-config/ssl"] @@ -54,15 +54,16 @@ tokio-net = { version = "0.2.0-alpha.6", features = ["signal"] } tokio-timer = "0.3.0-alpha.6" # unix domain sockets -mio-uds = { version="0.6.7", optional = true } +mio-uds = { version = "0.6.7", optional = true } #tokio-uds = { version="0.2.5", optional = true } # native-tls -native-tls = { version="0.2", optional = true } +native-tls = { version = "0.2", optional = true } +tokio-tls = { version = "0.3.0-alpha.6", optional = true } # openssl -openssl = { version="0.10", optional = true } -tokio-openssl = { version="0.4.0-alpha.6", optional = true } +openssl = { version = "0.10", optional = true } +tokio-openssl = { version = "0.4.0-alpha.6", optional = true } # rustls rustls = { version = "0.16.0", optional = true } diff --git a/actix-server/src/ssl/mod.rs b/actix-server/src/ssl/mod.rs index 6ce1222f..555f2301 100644 --- a/actix-server/src/ssl/mod.rs +++ b/actix-server/src/ssl/mod.rs @@ -11,7 +11,7 @@ pub use self::openssl::OpensslAcceptor; #[cfg(feature = "tls")] mod nativetls; #[cfg(feature = "tls")] -pub use self::nativetls::{NativeTlsAcceptor, TlsStream}; +pub use self::nativetls::NativeTlsAcceptor; #[cfg(feature = "rust-tls")] mod rustls; diff --git a/actix-server/src/ssl/nativetls.rs b/actix-server/src/ssl/nativetls.rs index 2c13ed5b..39074b98 100644 --- a/actix-server/src/ssl/nativetls.rs +++ b/actix-server/src/ssl/nativetls.rs @@ -1,18 +1,19 @@ use std::convert::Infallible; -use std::future::Future; -use std::io; use std::marker::PhantomData; -use std::pin::Pin; use std::task::{Context, Poll}; use actix_service::{Service, ServiceFactory}; -use futures::future; -use native_tls::{Error, HandshakeError, TlsAcceptor, TlsStream}; -use tokio_io::{AsyncRead, AsyncWrite}; +use futures::{ + future::{self, LocalBoxFuture}, + FutureExt as _, TryFutureExt as _, +}; +use native_tls::Error; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio_tls::{TlsAcceptor, TlsStream}; -use crate::counter::{Counter, CounterGuard}; +use crate::counter::Counter; use crate::ssl::MAX_CONN_COUNTER; -use crate::{Io, Protocol, ServerConfig}; +use crate::{Io, ServerConfig}; /// Support `SSL` connections via native-tls package /// @@ -22,8 +23,12 @@ pub struct NativeTlsAcceptor { io: PhantomData<(T, P)>, } -impl NativeTlsAcceptor { +impl NativeTlsAcceptor +where + T: AsyncRead + AsyncWrite + Unpin, +{ /// Create `NativeTlsAcceptor` instance + #[inline] pub fn new(acceptor: TlsAcceptor) -> Self { NativeTlsAcceptor { acceptor, @@ -33,6 +38,7 @@ impl NativeTlsAcceptor { } impl Clone for NativeTlsAcceptor { + #[inline] fn clone(&self) -> Self { Self { acceptor: self.acceptor.clone(), @@ -41,9 +47,13 @@ impl Clone for NativeTlsAcceptor { } } -impl ServiceFactory for NativeTlsAcceptor { +impl ServiceFactory for NativeTlsAcceptor +where + T: AsyncRead + AsyncWrite + Unpin + 'static, + P: 'static, +{ type Request = Io; - type Response = Io, P>; + type Response = Io, P>; type Error = Error; type Config = ServerConfig; @@ -70,141 +80,46 @@ pub struct NativeTlsAcceptorService { conns: Counter, } -impl Service for NativeTlsAcceptorService { - type Request = Io; - type Response = Io, P>; - type Error = Error; - type Future = Accept; +impl Clone for NativeTlsAcceptorService { + fn clone(&self) -> Self { + Self { + acceptor: self.acceptor.clone(), + io: PhantomData, + conns: self.conns.clone(), + } + } +} - fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll> { - if self.conns.available(ctx) { - Ok(Poll::Ready(Ok(()))) +impl Service for NativeTlsAcceptorService +where + T: AsyncRead + AsyncWrite + Unpin + 'static, + P: 'static, +{ + type Request = Io; + type Response = Io, P>; + type Error = Error; + type Future = LocalBoxFuture<'static, Result, P>, Error>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + if self.conns.available(cx) { + Poll::Ready(Ok(())) } else { - Ok(Poll::Pending) + Poll::Pending } } fn call(&mut self, req: Self::Request) -> Self::Future { - let (io, params, _) = req.into_parts(); - Accept { - _guard: self.conns.get(), - inner: Some(self.acceptor.accept(io)), - params: Some(params), - } - } -} - -/// Future returned from `NativeTlsAcceptor::accept` which will resolve -/// once the accept handshake has finished. -pub struct Accept { - inner: Option, HandshakeError>>, - params: Option

, - _guard: CounterGuard, -} - -impl Future for Accept { - type Output = Result, P>, Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let my = self.get_mut(); - match my.inner.take().expect("cannot poll MidHandshake twice") { - Ok(stream) => Poll::Ready(Ok(Io::from_parts( - NativeTlsStream { inner: stream }, - my.params.take().unwrap(), - Protocol::Unknown, - ))), - Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)), - Err(HandshakeError::WouldBlock(s)) => match s.handshake() { - Ok(stream) => Poll::Ready(Ok(Io::from_parts( - NativeTlsStream { inner: stream }, - my.params.take().unwrap(), - Protocol::Unknown, - ))), - Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)), - Err(HandshakeError::WouldBlock(s)) => { - my.inner = Some(Err(HandshakeError::WouldBlock(s))); - // TODO: should we use Waker somehow? - Poll::Pending - } - }, - } - } -} - -/// A wrapper around an underlying raw stream which implements the TLS or SSL -/// protocol. -/// -/// A `NativeTlsStream` represents a handshake that has been completed successfully -/// and both the server and the client are ready for receiving and sending -/// data. Bytes read from a `NativeTlsStream` are decrypted from `S` and bytes written -/// to a `NativeTlsStream` are encrypted when passing through to `S`. -#[derive(Debug)] -pub struct NativeTlsStream { - inner: TlsStream, -} - -impl AsRef> for NativeTlsStream { - fn as_ref(&self) -> &TlsStream { - &self.inner - } -} - -impl AsMut> for NativeTlsStream { - fn as_mut(&mut self) -> &mut TlsStream { - &mut self.inner - } -} - -impl io::Read for NativeTlsStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } -} - -impl io::Write for NativeTlsStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl AsyncRead for NativeTlsStream { - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - // TODO: wha? - unimplemented!() - } -} - -impl AsyncWrite for NativeTlsStream { - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - unimplemented!() - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unimplemented!() - } - - fn poll_shutdown( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - let inner = &mut Pin::get_mut(self).inner; - match inner.shutdown() { - Ok(_) => (), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (), - Err(e) => return Poll::Ready(Err(e)), - } - inner.get_mut().poll_shutdown() + let guard = self.conns.get(); + let this = self.clone(); + let (io, params, proto) = req.into_parts(); + async move { this.acceptor.accept(io).await } + .map_ok(move |stream| Io::from_parts(stream, params, proto)) + .map_ok(move |io| { + // Required to preserve `CounterGuard` until `Self::Future` + // is completely resolved. + let _ = guard; + io + }) + .boxed_local() } }