diff --git a/CHANGES.md b/CHANGES.md index bfd86a1a3..3dbb3795f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,10 @@ * Allow to customize connection handshake process via `HttpServer::listen_with()` and `HttpServer::bind_with()` methods +### Changed + +* native-tls - 0.2 + ### Fixed * Use zlib instead of raw deflate for decoding and encoding payloads with diff --git a/Cargo.toml b/Cargo.toml index 86cb53d10..3bfac16c1 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"] # openssl alpn = ["openssl", "tokio-openssl"] @@ -100,8 +100,7 @@ tokio-timer = "0.2" tokio-reactor = "0.1" # native-tls -native-tls = { version="0.1", optional = true } -tokio-tls = { version="0.1", optional = true } +native-tls = { version="0.2", optional = true } # openssl openssl = { version="0.10", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 626bb95f8..ed02b1b69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,8 +143,6 @@ extern crate serde_derive; #[cfg(feature = "tls")] extern crate native_tls; -#[cfg(feature = "tls")] -extern crate tokio_tls; #[cfg(feature = "openssl")] extern crate openssl; diff --git a/src/server/srv.rs b/src/server/http.rs similarity index 99% rename from src/server/srv.rs rename to src/server/http.rs index eaf7802c7..5deaf029b 100644 --- a/src/server/srv.rs +++ b/src/server/http.rs @@ -242,7 +242,7 @@ where pub fn listen_tls(self, lst: net::TcpListener, acceptor: TlsAcceptor) -> Self { use super::NativeTlsAcceptor; - Ok(self.listen_with(lst, NativeTlsAcceptor::new(acceptor))) + self.listen_with(lst, NativeTlsAcceptor::new(acceptor)) } #[cfg(feature = "alpn")] diff --git a/src/server/mod.rs b/src/server/mod.rs index f34497936..67952e433 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -23,22 +23,23 @@ pub(crate) mod message; pub(crate) mod output; mod server; pub(crate) mod settings; -mod srv; +mod http; mod ssl; mod worker; +use actix::Message; + pub use self::message::Request; pub use self::server::{ ConnectionRateTag, ConnectionTag, Connections, Server, Service, ServiceHandler, }; pub use self::settings::ServerSettings; -pub use self::srv::HttpServer; +pub use self::http::HttpServer; pub use self::ssl::*; #[doc(hidden)] pub use self::helpers::write_content_length; -use actix::Message; use body::Binary; use error::Error; use extensions::Extensions; diff --git a/src/server/ssl/mod.rs b/src/server/ssl/mod.rs index d99c4a584..b29a7d4a6 100644 --- a/src/server/ssl/mod.rs +++ b/src/server/ssl/mod.rs @@ -6,7 +6,7 @@ pub use self::openssl::OpensslAcceptor; #[cfg(feature = "tls")] mod nativetls; #[cfg(feature = "tls")] -pub use self::nativetls::NativeTlsAcceptor; +pub use self::nativetls::{TlsStream, NativeTlsAcceptor}; #[cfg(feature = "rust-tls")] mod rustls; diff --git a/src/server/ssl/nativetls.rs b/src/server/ssl/nativetls.rs index 8749599e9..c3f2c38d4 100644 --- a/src/server/ssl/nativetls.rs +++ b/src/server/ssl/nativetls.rs @@ -1,9 +1,9 @@ use std::net::Shutdown; use std::{io, time}; -use futures::{Future, Poll}; -use native_tls::TlsAcceptor; -use tokio_tls::{AcceptAsync, TlsAcceptorExt, TlsStream}; +use futures::{Async, Future, Poll}; +use native_tls::{self, TlsAcceptor, HandshakeError}; +use tokio_io::{AsyncRead, AsyncWrite}; use server::{AcceptorService, IoStream}; @@ -15,36 +15,41 @@ 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 } - } -} - -pub struct AcceptorFut(AcceptAsync); - -impl Future for AcceptorFut { - type Item = TlsStream; - type Error = io::Error; - - fn poll(&mut self) -> Poll { - self.0 - .poll() - .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) + NativeTlsAcceptor { acceptor: acceptor.into() } } } impl AcceptorService for NativeTlsAcceptor { type Accepted = TlsStream; - type Future = AcceptorFut; + type Future = Accept; fn scheme(&self) -> &'static str { "https" } fn accept(&self, io: Io) -> Self::Future { - AcceptorFut(TlsAcceptorExt::accept_async(&self.acceptor, io)) + Accept { inner: Some(self.acceptor.accept(io)) } } } @@ -65,3 +70,71 @@ 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() + } +} \ No newline at end of file