diff --git a/.travis.yml b/.travis.yml index e2d70678e..497f7bbc2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,12 +32,12 @@ script: - | if [[ "$TRAVIS_RUST_VERSION" != "stable" ]]; then cargo clean - cargo test --features="ssl" -- --nocapture + cargo test --features="ssl,tls" -- --nocapture fi - | if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install -f cargo-tarpaulin - cargo tarpaulin --features="ssl" --out Xml --no-count + cargo tarpaulin --features="ssl,tls" --out Xml --no-count bash <(curl -s https://codecov.io/bash) echo "Uploaded code coverage" fi diff --git a/Cargo.toml b/Cargo.toml index e17b72838..205e178b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ path = "src/lib.rs" default = ["session", "brotli", "flate2-c"] # tls -tls = ["native-tls", "tokio-tls"] +tls = ["native-tls", "tokio-tls", "actix-net/tls"] # openssl ssl = ["openssl", "tokio-openssl", "actix-net/ssl"] @@ -41,7 +41,7 @@ ssl = ["openssl", "tokio-openssl", "actix-net/ssl"] alpn = ["openssl", "tokio-openssl", "actix-net/ssl"] # rustls -rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] +rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots", "actix-net/rust-tls"] # unix sockets uds = ["tokio-uds"] diff --git a/src/server/http.rs b/src/server/http.rs index 263fd40a0..1cc899816 100644 --- a/src/server/http.rs +++ b/src/server/http.rs @@ -9,8 +9,8 @@ use net2::TcpBuilder; use num_cpus; use tokio_tcp::TcpStream; -//#[cfg(feature = "tls")] -//use native_tls::TlsAcceptor; +#[cfg(feature = "tls")] +use native_tls::TlsAcceptor; #[cfg(any(feature = "alpn", feature = "ssl"))] use openssl::ssl::SslAcceptorBuilder; @@ -258,16 +258,27 @@ where self } - // #[cfg(feature = "tls")] - // /// Use listener for accepting incoming tls connection requests - // /// - // /// HttpServer does not change any configuration for TcpListener, - // /// it needs to be configured before passing it to listen() method. - // pub fn listen_tls(self, lst: net::TcpListener, acceptor: TlsAcceptor) -> Self { - // use super::NativeTlsAcceptor; - // - // self.listen_with(lst, NativeTlsAcceptor::new(acceptor)) - // } + #[cfg(feature = "tls")] + /// Use listener for accepting incoming tls connection requests + /// + /// HttpServer does not change any configuration for TcpListener, + /// it needs to be configured before passing it to listen() method. + pub fn listen_tls(mut self, lst: net::TcpListener, acceptor: TlsAcceptor) -> Self { + use actix_net::service::NewServiceExt; + + let addr = lst.local_addr().unwrap(); + self.sockets.push(Socket { + lst, + addr, + scheme: "https", + handler: Box::new(HttpServiceBuilder::new( + self.factory.clone(), + move || ssl::NativeTlsAcceptor::new(acceptor.clone()).map_err(|_| ()), + DefaultPipelineFactory::new(), + )), + }); + self + } #[cfg(any(feature = "alpn", feature = "ssl"))] /// Use listener for accepting incoming tls connection requests diff --git a/src/server/ssl/mod.rs b/src/server/ssl/mod.rs index 7101de78a..7302cf0b4 100644 --- a/src/server/ssl/mod.rs +++ b/src/server/ssl/mod.rs @@ -3,10 +3,8 @@ mod openssl; #[cfg(any(feature = "alpn", feature = "ssl"))] pub use self::openssl::*; -//#[cfg(feature = "tls")] -//mod nativetls; -//#[cfg(feature = "tls")] -//pub use self::nativetls::{NativeTlsAcceptor, TlsStream}; +#[cfg(feature = "tls")] +mod nativetls; //#[cfg(feature = "rust-tls")] //mod rustls; diff --git a/src/server/ssl/nativetls.rs b/src/server/ssl/nativetls.rs index e35f12d2d..d59948c79 100644 --- a/src/server/ssl/nativetls.rs +++ b/src/server/ssl/nativetls.rs @@ -1,61 +1,9 @@ use std::net::Shutdown; use std::{io, time}; -use futures::{Async, Future, Poll}; -use native_tls::{self, HandshakeError, TlsAcceptor}; -use tokio_io::{AsyncRead, AsyncWrite}; +use actix_net::ssl::TlsStream; -use server::{AcceptorService, IoStream}; - -#[derive(Clone)] -/// Support `SSL` connections via native-tls package -/// -/// `tls` feature enables `NativeTlsAcceptor` type -pub struct NativeTlsAcceptor { - acceptor: TlsAcceptor, -} - -/// A wrapper around an underlying raw stream which implements the TLS or SSL -/// protocol. -/// -/// A `TlsStream` 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 `TlsStream` are decrypted from `S` and bytes written -/// to a `TlsStream` are encrypted when passing through to `S`. -#[derive(Debug)] -pub struct TlsStream { - inner: native_tls::TlsStream, -} - -/// Future returned from `NativeTlsAcceptor::accept` which will resolve -/// once the accept handshake has finished. -pub struct Accept { - inner: Option, HandshakeError>>, -} - -impl NativeTlsAcceptor { - /// Create `NativeTlsAcceptor` instance - pub fn new(acceptor: TlsAcceptor) -> Self { - NativeTlsAcceptor { - acceptor: acceptor.into(), - } - } -} - -impl AcceptorService for NativeTlsAcceptor { - type Accepted = TlsStream; - type Future = Accept; - - fn scheme(&self) -> &'static str { - "https" - } - - fn accept(&self, io: Io) -> Self::Future { - Accept { - inner: Some(self.acceptor.accept(io)), - } - } -} +use server::IoStream; impl IoStream for TlsStream { #[inline] @@ -74,70 +22,3 @@ impl IoStream for TlsStream { self.get_mut().get_mut().set_linger(dur) } } - -impl Future for Accept { - type Item = TlsStream; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - match self.inner.take().expect("cannot poll MidHandshake twice") { - Ok(stream) => Ok(TlsStream { inner: stream }.into()), - Err(HandshakeError::Failure(e)) => { - Err(io::Error::new(io::ErrorKind::Other, e)) - } - Err(HandshakeError::WouldBlock(s)) => match s.handshake() { - Ok(stream) => Ok(TlsStream { inner: stream }.into()), - Err(HandshakeError::Failure(e)) => { - Err(io::Error::new(io::ErrorKind::Other, e)) - } - Err(HandshakeError::WouldBlock(s)) => { - self.inner = Some(Err(HandshakeError::WouldBlock(s))); - Ok(Async::NotReady) - } - }, - } - } -} - -impl TlsStream { - /// Get access to the internal `native_tls::TlsStream` stream which also - /// transitively allows access to `S`. - pub fn get_ref(&self) -> &native_tls::TlsStream { - &self.inner - } - - /// Get mutable access to the internal `native_tls::TlsStream` stream which - /// also transitively allows mutable access to `S`. - pub fn get_mut(&mut self) -> &mut native_tls::TlsStream { - &mut self.inner - } -} - -impl io::Read for TlsStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.read(buf) - } -} - -impl io::Write for TlsStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl AsyncRead for TlsStream {} - -impl AsyncWrite for TlsStream { - fn shutdown(&mut self) -> Poll<(), io::Error> { - match self.inner.shutdown() { - Ok(_) => (), - Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (), - Err(e) => return Err(e), - } - self.inner.get_mut().shutdown() - } -}