1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-06-26 19:47:43 +02:00

refactor server configuration and tls support

This commit is contained in:
Nikolay Kim
2019-12-02 11:30:27 +06:00
parent 16ff283fb2
commit 9fbe6a1f6d
21 changed files with 366 additions and 526 deletions

90
actix-tls/CHANGES.md Normal file
View File

@ -0,0 +1,90 @@
# Changes
## [0.3.0] - 2019-10-03
### Changed
* Update `rustls` to 0.16
* Minimum required Rust version upped to 1.37.0
## [0.2.5] - 2019-09-05
* Add `TcpConnectService`
## [0.2.4] - 2019-09-02
* Use arbiter's storage for default async resolver
## [0.2.3] - 2019-08-05
* Add `ConnectService` and `OpensslConnectService`
## [0.2.2] - 2019-07-24
* Add `rustls` support
## [0.2.1] - 2019-07-17
### Added
* Expose Connect addrs #30
### Changed
* Update `derive_more` to 0.15
## [0.2.0] - 2019-05-12
### Changed
* Upgrade to actix-service 0.4
## [0.1.5] - 2019-04-19
### Added
* `Connect::set_addr()`
### Changed
* Use trust-dns-resolver 0.11.0
## [0.1.4] - 2019-04-12
### Changed
* Do not start default resolver immediately for default connector.
## [0.1.3] - 2019-04-11
### Changed
* Start trust-dns default resolver on first use
## [0.1.2] - 2019-04-04
### Added
* Log error if dns system config could not be loaded.
### Changed
* Rename connect Connector to TcpConnector #10
## [0.1.1] - 2019-03-15
### Fixed
* Fix error handling for single address
## [0.1.0] - 2019-03-14
* Refactor resolver and connector services
* Rename crate

57
actix-tls/Cargo.toml Normal file
View File

@ -0,0 +1,57 @@
[package]
name = "actix-tls"
version = "1.0.0-alpha.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix tls services"
keywords = ["network", "framework", "async", "futures"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-tls/"
categories = ["network-programming", "asynchronous"]
license = "MIT/Apache-2.0"
edition = "2018"
workspace = ".."
[package.metadata.docs.rs]
features = ["server", "openssl", "rustls"]
[lib]
name = "actix_tls"
path = "src/lib.rs"
[features]
default = []
# openssl
openssl = ["open-ssl", "tokio-openssl"]
# rustls
rustls = ["rust-tls", "webpki"]
[dependencies]
actix-service = "1.0.0-alpha.1"
actix-codec = "0.2.0-alpha.1"
actix-utils = "0.5.0-alpha.1"
actix-rt = "1.0.0-alpha.1"
derive_more = "0.99"
either = "1.5.2"
futures = "0.3.1"
log = "0.4"
# server feature
actix-server = { version = "0.8.0-alpha.1", optional=true }
# openssl
open-ssl = { version="0.10", package = "openssl", optional = true }
tokio-openssl = { version = "=0.4.0-alpha.6", optional = true }
# rustls
rust-tls = { version = "0.16.0", package = "rustls", optional = true }
webpki = { version = "0.21", optional = true }
webpki-roots = { version = "0.17", optional = true }
# tokio-rustls = { version = "0.12.0-alpha.2", optional = true }
# tokio-rustls = { git = "https://github.com/quininer/tokio-rustls.git", branch = "tokio-0.2", optional = true }
[dev-dependencies]
bytes = "0.4"
actix-testing = { version="0.3.0-alpha.1" }

1
actix-tls/LICENSE-APACHE Symbolic link
View File

@ -0,0 +1 @@
../LICENSE-APACHE

1
actix-tls/LICENSE-MIT Symbolic link
View File

@ -0,0 +1 @@
../LICENSE-MIT

51
actix-tls/src/lib.rs Normal file
View File

@ -0,0 +1,51 @@
//! SSL Services
use std::sync::atomic::{AtomicUsize, Ordering};
use actix_utils::counter::Counter;
#[cfg(feature = "openssl")]
pub mod openssl;
//#[cfg(feature = "rustls")]
//mod rustls;
//#[cfg(feature = "rustls")]
//pub use self::rustls::RustlsAcceptor;
/// Sets the maximum per-worker concurrent ssl connection establish process.
///
/// All listeners will stop accepting connections when this limit is
/// reached. It can be used to limit the global SSL CPU usage.
///
/// By default max connections is set to a 256.
pub fn max_concurrent_ssl_connect(num: usize) {
MAX_CONN.store(num, Ordering::Relaxed);
}
pub(crate) static MAX_CONN: AtomicUsize = AtomicUsize::new(256);
thread_local! {
static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed));
}
/// Ssl error combinded with service error.
#[derive(Debug)]
pub enum SslError<E1, E2> {
Ssl(E1),
Service(E2),
}
pub trait ServerBuilderExt: Sized {
/// Sets the maximum per-worker concurrent connection establish process.
///
/// All listeners will stop accepting connections when this limit is reached. It
/// can be used to limit the global SSL CPU usage.
///
/// By default max connections is set to a 256.
fn maxconnrate(self, num: usize) -> Self {
max_concurrent_ssl_connect(num);
self
}
}
#[cfg(feature = "server")]
impl ServerBuilderExt for actix_server::ServerBuilder {}

111
actix-tls/src/openssl.rs Normal file
View File

@ -0,0 +1,111 @@
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
pub use tokio_openssl::{HandshakeError, SslStream};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::{Service, ServiceFactory};
use actix_utils::counter::{Counter, CounterGuard};
use futures::future::{ok, FutureExt, LocalBoxFuture, Ready};
use open_ssl::ssl::SslAcceptor;
use crate::MAX_CONN_COUNTER;
/// Support `TLS` server connections via openssl package
///
/// `openssl` feature enables `Acceptor` type
pub struct Acceptor<T: AsyncRead + AsyncWrite> {
acceptor: SslAcceptor,
io: PhantomData<T>,
}
impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
/// Create default `OpensslAcceptor`
pub fn new(acceptor: SslAcceptor) -> Self {
Acceptor {
acceptor,
io: PhantomData,
}
}
}
impl<T: AsyncRead + AsyncWrite> Clone for Acceptor<T> {
fn clone(&self) -> Self {
Self {
acceptor: self.acceptor.clone(),
io: PhantomData,
}
}
}
impl<T: AsyncRead + AsyncWrite + Unpin + 'static> ServiceFactory for Acceptor<T> {
type Request = T;
type Response = SslStream<T>;
type Error = HandshakeError<T>;
type Config = ();
type Service = AcceptorService<T>;
type InitError = ();
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: &()) -> Self::Future {
MAX_CONN_COUNTER.with(|conns| {
ok(AcceptorService {
acceptor: self.acceptor.clone(),
conns: conns.clone(),
io: PhantomData,
})
})
}
}
pub struct AcceptorService<T> {
acceptor: SslAcceptor,
conns: Counter,
io: PhantomData<T>,
}
impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Service for AcceptorService<T> {
type Request = T;
type Response = SslStream<T>;
type Error = HandshakeError<T>;
type Future = AcceptorServiceResponse<T>;
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
if self.conns.available(ctx) {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
}
fn call(&mut self, req: Self::Request) -> Self::Future {
let acc = self.acceptor.clone();
AcceptorServiceResponse {
_guard: self.conns.get(),
fut: async move {
let acc = acc;
tokio_openssl::accept(&acc, req).await
}
.boxed_local(),
}
}
}
pub struct AcceptorServiceResponse<T>
where
T: AsyncRead + AsyncWrite,
{
fut: LocalBoxFuture<'static, Result<SslStream<T>, HandshakeError<T>>>,
_guard: CounterGuard,
}
impl<T: AsyncRead + AsyncWrite + Unpin> Future for AcceptorServiceResponse<T> {
type Output = Result<SslStream<T>, HandshakeError<T>>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let io = futures::ready!(Pin::new(&mut self.fut).poll(cx))?;
Poll::Ready(Ok(io))
}
}