diff --git a/.travis.yml b/.travis.yml
index 48a1414ac..767e9fde6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,12 +32,12 @@ script:
- |
if [[ "$TRAVIS_RUST_VERSION" != "nightly" ]]; then
cargo clean
- cargo test --features="ssl,tls" -- --nocapture
+ cargo test --features="ssl,tls,rust-tls" -- --nocapture
fi
- |
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install -f cargo-tarpaulin
- cargo tarpaulin --features="ssl,tls" --out Xml
+ cargo tarpaulin --features="ssl,tls,rust-tls" --out Xml
bash <(curl -s https://codecov.io/bash)
echo "Uploaded code coverage"
fi
@@ -46,7 +46,7 @@ script:
after_success:
- |
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "beta" ]]; then
- cargo doc --features "ssl,tls" --no-deps &&
+ cargo doc --features "ssl,tls,rust-tls" --no-deps &&
echo "" > target/doc/index.html &&
git clone https://github.com/davisp/ghp-import.git &&
./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc &&
diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs
index 81a364df5..906ee615c 100644
--- a/src/ssl/mod.rs
+++ b/src/ssl/mod.rs
@@ -13,7 +13,10 @@ mod nativetls;
#[cfg(feature = "tls")]
pub use self::nativetls::{NativeTlsAcceptor, TlsStream};
-pub(crate) const MAX_CONN: AtomicUsize = AtomicUsize::new(256);
+#[cfg(feature = "rust-tls")]
+mod rustls;
+#[cfg(feature = "rust-tls")]
+pub use self::rustls::RustlsAcceptor;
/// Sets the maximum per-worker concurrent ssl connection establish process.
///
@@ -25,11 +28,8 @@ pub fn max_concurrent_ssl_connect(num: usize) {
MAX_CONN.store(num, Ordering::Relaxed);
}
+pub(crate) const MAX_CONN: AtomicUsize = AtomicUsize::new(256);
+
thread_local! {
static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed));
}
-
-// #[cfg(feature = "rust-tls")]
-// mod rustls;
-// #[cfg(feature = "rust-tls")]
-// pub use self::rustls::RustlsAcceptor;
diff --git a/src/ssl/rustls.rs b/src/ssl/rustls.rs
new file mode 100644
index 000000000..ef4c966be
--- /dev/null
+++ b/src/ssl/rustls.rs
@@ -0,0 +1,103 @@
+use std::io;
+use std::marker::PhantomData;
+use std::sync::Arc;
+
+use futures::{future::ok, future::FutureResult, Async, Future, Poll};
+use rustls::{ServerConfig, ServerSession};
+use tokio_io::{AsyncRead, AsyncWrite};
+use tokio_rustls::{AcceptAsync, ServerConfigExt, TlsStream};
+
+use super::MAX_CONN_COUNTER;
+use counter::{Counter, CounterGuard};
+use service::{NewService, Service};
+
+/// Support `SSL` connections via rustls package
+///
+/// `rust-tls` feature enables `RustlsAcceptor` type
+pub struct RustlsAcceptor {
+ config: Arc,
+ io: PhantomData,
+}
+
+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 = T;
+ type Response = TlsStream;
+ type Error = io::Error;
+ type Service = RustlsAcceptorService;
+ type InitError = ();
+ type Future = FutureResult;
+
+ fn new_service(&self) -> Self::Future {
+ MAX_CONN_COUNTER.with(|conns| {
+ ok(RustlsAcceptorService {
+ config: self.config.clone(),
+ conns: conns.clone(),
+ io: PhantomData,
+ })
+ })
+ }
+}
+
+pub struct RustlsAcceptorService {
+ config: Arc,
+ io: PhantomData,
+ conns: Counter,
+}
+
+impl Service for RustlsAcceptorService {
+ type Request = T;
+ type Response = TlsStream;
+ type Error = io::Error;
+ type Future = RustlsAcceptorServiceFut;
+
+ fn poll_ready(&mut self) -> Poll<(), Self::Error> {
+ if self.conns.available() {
+ Ok(Async::Ready(()))
+ } else {
+ Ok(Async::NotReady)
+ }
+ }
+
+ fn call(&mut self, req: Self::Request) -> Self::Future {
+ RustlsAcceptorServiceFut {
+ _guard: self.conns.get(),
+ fut: ServerConfigExt::accept_async(&self.config, req),
+ }
+ }
+}
+
+pub struct RustlsAcceptorServiceFut
+where
+ T: AsyncRead + AsyncWrite,
+{
+ fut: AcceptAsync,
+ _guard: CounterGuard,
+}
+
+impl Future for RustlsAcceptorServiceFut {
+ type Item = TlsStream;
+ type Error = io::Error;
+
+ fn poll(&mut self) -> Poll {
+ self.fut.poll()
+ }
+}