1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-08-13 22:28:22 +02:00

Compare commits

..

9 Commits

Author SHA1 Message Date
Rob Ede
93865de848 move router to actix-router 2020-12-31 02:29:27 +00:00
Rob Ede
6bcf6d8160 use bytestring crate name as dir name 2020-12-31 02:21:50 +00:00
Rob Ede
14ff379150 prepare bytestring release 1.0.0 (#243) 2020-12-31 02:20:49 +00:00
fakeshadow
647817ef14 tokio 1.0 and mio 0.7 (#204) 2020-12-30 22:11:50 +00:00
fakeshadow
b5eefb4d42 merge actix-testing into actix-server (#242) 2020-12-29 21:20:24 +00:00
fakeshadow
03eb96d6d4 fix actix-tls tests (#241) 2020-12-29 11:36:17 +00:00
Rob Ede
0934078947 prepare tls beta release 2020-12-29 01:04:21 +00:00
Rob Ede
5759c9e144 merge -connect and -tls and upgrade to rt v2 (#238) 2020-12-29 00:38:41 +00:00
Rob Ede
3c6de3a81b use correct service version for tracing 2020-12-29 00:08:59 +00:00
52 changed files with 487 additions and 742 deletions

View File

@@ -1,31 +1,27 @@
[workspace]
members = [
"actix-codec",
"actix-connect",
"actix-rt",
"actix-macros",
"actix-service",
"actix-router",
"actix-rt",
"actix-server",
"actix-testing",
"actix-service",
"actix-threadpool",
"actix-tls",
"actix-tracing",
"actix-utils",
"router",
"string",
"bytestring",
]
[patch.crates-io]
actix-codec = { git = "https://github.com/actix/actix-net.git", rev = "ba44ea7d0bafaf5fccb9a34003d503e1910943ee" }
actix-connect = { path = "actix-connect" }
actix-rt = { git = "https://github.com/actix/actix-net.git", rev = "ba44ea7d0bafaf5fccb9a34003d503e1910943ee" }
actix-codec = { path = "actix-codec" }
actix-macros = { path = "actix-macros" }
actix-router = { path = "actix-router" }
actix-rt = { path = "actix-rt" }
actix-server = { path = "actix-server" }
actix-service = { git = "https://github.com/actix/actix-net.git", rev = "ba44ea7d0bafaf5fccb9a34003d503e1910943ee" }
actix-testing = { path = "actix-testing" }
actix-service = { path = "actix-service" }
actix-threadpool = { path = "actix-threadpool" }
actix-tls = { path = "actix-tls" }
actix-tracing = { path = "actix-tracing" }
actix-utils = { git = "https://github.com/actix/actix-net.git", rev = "ba44ea7d0bafaf5fccb9a34003d503e1910943ee" }
actix-router = { path = "router" }
bytestring = { path = "string" }
actix-utils = { path = "actix-utils" }
bytestring = { path = "bytestring" }

View File

@@ -1,154 +0,0 @@
# Changes
## Unreleased - 2020-xx-xx
## 2.0.0 - 2020-09-02
- No significant changes from `2.0.0-alpha.4`.
## 2.0.0-alpha.4 - 2020-08-17
### Changed
* Update `rustls` dependency to 0.18
* Update `tokio-rustls` dependency to 0.14
## [2.0.0-alpha.3] - 2020-05-08
### Fixed
* Corrected spelling of `ConnectError::Unresolverd` to `ConnectError::Unresolved`
## [2.0.0-alpha.2] - 2020-03-08
### Changed
* Update `trust-dns-proto` dependency to 0.19. [#116]
* Update `trust-dns-resolver` dependency to 0.19. [#116]
* `Address` trait is now required to have static lifetime. [#116]
* `start_resolver` and `start_default_resolver` are now `async` and may return a `ConnectError`. [#116]
[#116]: https://github.com/actix/actix-net/pull/116
## [2.0.0-alpha.1] - 2020-03-03
### Changed
* Update `rustls` dependency to 0.17
* Update `tokio-rustls` dependency to 0.13
## [1.0.2] - 2020-01-15
* Fix actix-service 1.0.3 compatibility
## [1.0.1] - 2019-12-15
* Fix trust-dns-resolver compilation
## [1.0.0] - 2019-12-11
* Release
## [1.0.0-alpha.3] - 2019-12-07
### Changed
* Migrate to tokio 0.2
## [1.0.0-alpha.2] - 2019-12-02
### Changed
* Migrated to `std::future`
## [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

View File

@@ -1,58 +0,0 @@
[package]
name = "actix-connect"
version = "2.0.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "TCP connector service for Actix ecosystem."
keywords = ["network", "framework", "async", "futures"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-connect/"
categories = ["network-programming", "asynchronous"]
license = "MIT OR Apache-2.0"
edition = "2018"
[package.metadata.docs.rs]
features = ["openssl", "rustls", "uri"]
[lib]
name = "actix_connect"
path = "src/lib.rs"
[features]
default = ["uri"]
# openssl
openssl = ["open-ssl", "tokio-openssl"]
# rustls
rustls = ["rust-tls", "tokio-rustls", "webpki"]
# support http::Uri as connect address
uri = ["http"]
[dependencies]
actix-service = "1.0.6"
actix-codec = "0.3.0"
actix-utils = "2.0.0"
actix-rt = "1.1.1"
derive_more = "0.99.2"
either = "1.5.3"
futures-util = { version = "0.3.4", default-features = false }
http = { version = "0.2.0", optional = true }
log = "0.4"
trust-dns-proto = { version = "0.19", default-features = false, features = ["tokio-runtime"] }
trust-dns-resolver = { version = "0.19", default-features = false, features = ["tokio-runtime", "system-config"] }
# openssl
open-ssl = { package = "openssl", version = "0.10", optional = true }
tokio-openssl = { version = "0.4.0", optional = true }
# rustls
rust-tls = { package = "rustls", version = "0.18.0", optional = true }
tokio-rustls = { version = "0.14.0", optional = true }
webpki = { version = "0.21", optional = true }
[dev-dependencies]
bytes = "0.5.3"
actix-testing = "1.0.0"

View File

@@ -22,8 +22,8 @@ regex = "1.3.1"
serde = "1.0.104"
bytestring = "0.1.2"
log = "0.4.8"
http = { version = "0.2.0", optional = true }
http = { version = "0.2.2", optional = true }
[dev-dependencies]
http = "0.2.0"
http = "0.2.2"
serde_derive = "1.0"

View File

@@ -1,7 +1,7 @@
# Changes
## Unreleased - 2020-xx-xx
* Merge `actix-testing` to `actix-server` as `test_server` mod.
## 2.0.0-beta.1 - 2020-12-28
* Added explicit info log message on accept queue pause. [#215]

View File

@@ -36,7 +36,6 @@ slab = "0.4"
tokio = { version = "1", features = ["sync"] }
[dev-dependencies]
actix-testing = "2.0.0-beta.1"
bytes = "1"
env_logger = "0.8"
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }

View File

@@ -11,6 +11,7 @@ mod server;
mod service;
mod signals;
mod socket;
mod test_server;
mod waker_queue;
mod worker;
@@ -18,6 +19,7 @@ pub use self::builder::ServerBuilder;
pub use self::config::{ServiceConfig, ServiceRuntime};
pub use self::server::Server;
pub use self::service::ServiceFactory;
pub use self::test_server::TestServer;
#[doc(hidden)]
pub use self::socket::FromStream;

View File

@@ -1,19 +1,9 @@
//! Various helpers for Actix applications to use during testing.
#![deny(rust_2018_idioms, nonstandard_style)]
#![allow(clippy::type_complexity, clippy::needless_doctest_main)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use std::sync::mpsc;
use std::{net, thread};
use actix_rt::{net::TcpStream, System};
use actix_server::{Server, ServerBuilder, ServiceFactory};
use socket2::{Domain, Protocol, Socket, Type};
#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub use actix_macros::test;
use crate::{Server, ServerBuilder, ServiceFactory};
/// The `TestServer` type.
///
@@ -24,7 +14,7 @@ pub use actix_macros::test;
///
/// ```rust
/// use actix_service::fn_service;
/// use actix_testing::TestServer;
/// use actix_server::TestServer;
///
/// #[actix_rt::main]
/// async fn main() {
@@ -115,11 +105,10 @@ impl TestServer {
/// Get first available unused local address
pub fn unused_addr() -> net::SocketAddr {
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
let socket =
Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap();
socket.bind(&addr.into()).unwrap();
socket.set_reuse_address(true).unwrap();
let tcp = socket.into_tcp_listener();
let socket = mio::net::TcpSocket::new_v4().unwrap();
socket.bind(addr).unwrap();
socket.set_reuseaddr(true).unwrap();
let tcp = socket.listen(1024).unwrap();
tcp.local_addr().unwrap()
}
}

View File

@@ -6,7 +6,7 @@ use super::{IntoServiceFactory, ServiceFactory};
///
/// Note that this function consumes the receiving service factory and returns
/// a wrapped version of it.
pub fn map_config<I, SF, S, Req, F, Cfg>(factory: I, f: F) -> MapConfig<SF, Req, F, Cfg>
pub fn map_config<I, SF, Req, F, Cfg>(factory: I, f: F) -> MapConfig<SF, Req, F, Cfg>
where
I: IntoServiceFactory<SF, Req>,
SF: ServiceFactory<Req>,

View File

@@ -1,37 +0,0 @@
# Changes
## Unreleased - 2021-xx-xx
## 2.0.0-beta.1 - 2020-12-28
* Update `actix-server` to v2.0.0-beta.1.
## 1.0.1 - 2020-05-19
* Replace deprecated `net2` crate with `socket2`
* Remove unused `futures` dependency
## 1.0.0 - 2019-12-11
* Update actix-server to 1.0.0
## 1.0.0-alpha.3 - 2019-12-07
* Migrate to tokio 0.2
## 1.0.0-alpha.2 - 2019-12-02
* Re-export `test` attribute macros
## 0.3.0-alpha.1 - 2019-11-22
* Migrate to std::future
## 0.2.0 - 2019-10-14
* Upgrade actix-server and actix-server-config deps
## 0.1.0 - 2019-09-25
* Initial impl

View File

@@ -1,26 +0,0 @@
[package]
name = "actix-testing"
version = "2.0.0-beta.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Various helpers for Actix applications to use during testing"
keywords = ["network", "framework", "async", "futures"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-testing/"
categories = ["network-programming", "asynchronous"]
license = "MIT OR Apache-2.0"
edition = "2018"
readme = "README.md"
[lib]
name = "actix_testing"
path = "src/lib.rs"
[dependencies]
actix-rt = "2.0.0-beta.1"
actix-macros = "0.1.0"
actix-server = "2.0.0-beta.1"
actix-service = "2.0.0-beta.1"
log = "0.4"
socket2 = "0.3"

View File

@@ -1,9 +0,0 @@
# Actix test utilities [![crates.io](https://meritbadge.herokuapp.com/actix-testing)](https://crates.io/crates/actix-testint) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Documentation & community resources
* [User Guide](https://actix.rs/docs/)
* [API Documentation](https://docs.rs/actix-testing/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-http-test](https://crates.io/crates/actix-testing)
* Minimum supported Rust version: 1.46 or later

View File

@@ -19,7 +19,7 @@ path = "src/lib.rs"
[dependencies]
derive_more = "0.99.2"
futures-channel = "0.3.1"
futures-channel = "0.3.7"
parking_lot = "0.11"
lazy_static = "1.3"
log = "0.4"

View File

@@ -1,6 +1,14 @@
# Changes
## Unreleased - 2020-xx-xx
## Unreleased - 2021-xx-xx
## 3.0.0-beta.1 - 2020-12-29
* Move acceptors under `accept` module. [#238]
* Merge `actix-connect` crate under `connect` module. [#238]
* Add feature flags to enable acceptors and/or connectors individually. [#238]
[#238]: https://github.com/actix/actix-net/pull/238
## 2.0.0 - 2020-09-03

View File

@@ -1,9 +1,9 @@
[package]
name = "actix-tls"
version = "2.0.0"
version = "3.0.0-beta.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "TLS acceptor services for Actix ecosystem."
keywords = ["network", "framework", "async", "tls", "ssl"]
description = "TLS acceptor and connector services for Actix ecosystem"
keywords = ["network", "tls", "ssl", "async", "transport"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-tls/"
@@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
edition = "2018"
[package.metadata.docs.rs]
features = ["openssl", "rustls", "nativetls"]
features = ["openssl", "rustls", "native-tls", "accept", "connect", "uri"]
[lib]
name = "actix_tls"
@@ -20,45 +20,64 @@ path = "src/lib.rs"
[[example]]
name = "basic"
required-features = ["rustls"]
required-features = ["accept", "rustls"]
[features]
default = []
default = ["accept", "connect", "uri"]
# openssl
openssl = ["open-ssl", "tokio-openssl"]
# enable acceptor services
accept = []
# rustls
rustls = ["rust-tls", "webpki", "webpki-roots", "tokio-rustls"]
# enable connector services
connect = ["trust-dns-proto/tokio-runtime", "trust-dns-resolver/tokio-runtime", "trust-dns-resolver/system-config"]
# nativetls
nativetls = ["native-tls", "tokio-tls"]
# use openssl impls
openssl = ["tls-openssl", "tokio-openssl"]
# use rustls impls
rustls = ["tls-rustls", "webpki", "webpki-roots", "tokio-rustls"]
# use native-tls impls
native-tls = ["tls-native-tls", "tokio-native-tls"]
# support http::Uri as connect address
uri = ["http"]
[dependencies]
actix-service = "1.0.0"
actix-codec = "0.3.0"
actix-utils = "2.0.0"
actix-codec = "0.4.0-beta.1"
actix-rt = "2.0.0-beta.1"
actix-service = "2.0.0-beta.1"
actix-utils = "3.0.0-beta.1"
futures-util = { version = "0.3.4", default-features = false }
derive_more = "0.99.5"
either = "1.6"
futures-util = { version = "0.3.7", default-features = false }
http = { version = "0.2.2", optional = true }
log = "0.4"
# resolver
trust-dns-proto = { version = "0.20.0", default-features = false, optional = true }
trust-dns-resolver = { version = "0.20.0", default-features = false, optional = true }
# openssl
open-ssl = { package = "openssl", version = "0.10", optional = true }
tokio-openssl = { version = "0.4.0", optional = true }
tls-openssl = { package = "openssl", version = "0.10", optional = true }
tokio-openssl = { version = "0.6", optional = true }
# TODO: Reduce dependencies where tokio wrappers re-export base crate.
# rustls
rust-tls = { package = "rustls", version = "0.18.0", optional = true }
tls-rustls = { package = "rustls", version = "0.19", optional = true }
tokio-rustls = { version = "0.22", optional = true }
webpki = { version = "0.21", optional = true }
webpki-roots = { version = "0.20", optional = true }
tokio-rustls = { version = "0.14.0", optional = true }
webpki-roots = { version = "0.21", optional = true }
# native-tls
native-tls = { version = "0.2", optional = true }
tokio-tls = { version = "0.3", optional = true }
tls-native-tls = { package = "native-tls", version = "0.2", optional = true }
tokio-native-tls = { version = "0.3", optional = true }
[dev-dependencies]
bytes = "0.5"
log = "0.4"
env_logger = "0.7"
actix-testing = "2.0.0-beta.1"
actix-server = "2.0.0-beta.1"
actix-rt = "1"
bytes = "1"
env_logger = "0.8"
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
log = "0.4"

View File

@@ -15,6 +15,10 @@
//! http --verify=false https://127.0.0.1:8443
//! ```
// this rename only exists because of how we have organised the crate's feature flags
// it is not necessary for your actual code
extern crate tls_rustls as rustls;
use std::{
env,
fs::File,
@@ -27,10 +31,10 @@ use std::{
use actix_server::Server;
use actix_service::pipeline_factory;
use actix_tls::rustls::Acceptor as RustlsAcceptor;
use actix_tls::accept::rustls::Acceptor as RustlsAcceptor;
use futures_util::future::ok;
use log::info;
use rust_tls::{
use rustls::{
internal::pemfile::certs, internal::pemfile::rsa_private_keys, NoClientAuth, ServerConfig,
};

View File

@@ -0,0 +1,42 @@
//! TLS acceptor services for Actix ecosystem.
//!
//! ## Crate Features
//! * `openssl` - TLS acceptor using the `openssl` crate.
//! * `rustls` - TLS acceptor using the `rustls` crate.
//! * `native-tls` - TLS acceptor using the `native-tls` crate.
use std::sync::atomic::{AtomicUsize, Ordering};
use actix_utils::counter::Counter;
#[cfg(feature = "openssl")]
pub mod openssl;
#[cfg(feature = "rustls")]
pub mod rustls;
#[cfg(feature = "native-tls")]
pub mod nativetls;
pub(crate) static MAX_CONN: AtomicUsize = AtomicUsize::new(256);
thread_local! {
static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed));
}
/// Sets the maximum per-worker concurrent TLS connection limit.
///
/// All listeners will stop accepting connections when this limit is reached.
/// It can be used to regulate the global TLS CPU usage.
///
/// By default, the connection limit is 256.
pub fn max_concurrent_tls_connect(num: usize) {
MAX_CONN.store(num, Ordering::Relaxed);
}
/// TLS error combined with service error.
#[derive(Debug)]
pub enum TlsError<E1, E2> {
Tls(E1),
Service(E2),
}

View File

@@ -1,93 +1,79 @@
use std::marker::PhantomData;
use std::task::{Context, Poll};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::{Service, ServiceFactory};
use actix_utils::counter::Counter;
use futures_util::future::{self, FutureExt, LocalBoxFuture, TryFutureExt};
use futures_util::future::{ready, LocalBoxFuture, Ready};
pub use native_tls::Error;
pub use tokio_tls::{TlsAcceptor, TlsStream};
pub use tokio_native_tls::{TlsAcceptor, TlsStream};
use crate::MAX_CONN_COUNTER;
use super::MAX_CONN_COUNTER;
/// Accept TLS connections via `native-tls` package.
///
/// `nativetls` feature enables this `Acceptor` type.
pub struct Acceptor<T> {
/// `native-tls` feature enables this `Acceptor` type.
pub struct Acceptor {
acceptor: TlsAcceptor,
io: PhantomData<T>,
}
impl<T> Acceptor<T>
where
T: AsyncRead + AsyncWrite + Unpin,
{
impl Acceptor {
/// Create `native-tls` based `Acceptor` service factory.
#[inline]
pub fn new(acceptor: TlsAcceptor) -> Self {
Acceptor {
acceptor,
io: PhantomData,
}
Acceptor { acceptor }
}
}
impl<T> Clone for Acceptor<T> {
impl Clone for Acceptor {
#[inline]
fn clone(&self) -> Self {
Self {
acceptor: self.acceptor.clone(),
io: PhantomData,
}
}
}
impl<T> ServiceFactory for Acceptor<T>
impl<T> ServiceFactory<T> for Acceptor
where
T: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Request = T;
type Response = TlsStream<T>;
type Error = Error;
type Service = NativeTlsAcceptorService<T>;
type Config = ();
type Service = NativeTlsAcceptorService;
type InitError = ();
type Future = future::Ready<Result<Self::Service, Self::InitError>>;
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
MAX_CONN_COUNTER.with(|conns| {
future::ok(NativeTlsAcceptorService {
ready(Ok(NativeTlsAcceptorService {
acceptor: self.acceptor.clone(),
conns: conns.clone(),
io: PhantomData,
})
}))
})
}
}
pub struct NativeTlsAcceptorService<T> {
pub struct NativeTlsAcceptorService {
acceptor: TlsAcceptor,
io: PhantomData<T>,
conns: Counter,
}
impl<T> Clone for NativeTlsAcceptorService<T> {
impl Clone for NativeTlsAcceptorService {
fn clone(&self) -> Self {
Self {
acceptor: self.acceptor.clone(),
io: PhantomData,
conns: self.conns.clone(),
}
}
}
impl<T> Service for NativeTlsAcceptorService<T>
impl<T> Service<T> for NativeTlsAcceptorService
where
T: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Request = T;
type Response = TlsStream<T>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<TlsStream<T>, Error>>;
@@ -100,15 +86,13 @@ where
}
}
fn call(&mut self, req: Self::Request) -> Self::Future {
fn call(&mut self, io: T) -> Self::Future {
let guard = self.conns.get();
let this = self.clone();
async move { this.acceptor.accept(req).await }
.map_ok(move |io| {
// Required to preserve `CounterGuard` until `Self::Future` is completely resolved.
let _ = guard;
io
})
.boxed_local()
Box::pin(async move {
let io = this.acceptor.accept(io).await;
drop(guard);
io
})
}
}

View File

@@ -1,77 +1,78 @@
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::{Service, ServiceFactory};
use actix_utils::counter::{Counter, CounterGuard};
use futures_util::future::{ok, FutureExt, LocalBoxFuture, Ready};
use futures_util::{
future::{ready, Ready},
ready,
};
pub use open_ssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
pub use tokio_openssl::{HandshakeError, SslStream};
pub use openssl::ssl::{
AlpnError, Error as SslError, HandshakeError, Ssl, SslAcceptor, SslAcceptorBuilder,
};
pub use tokio_openssl::SslStream;
use crate::MAX_CONN_COUNTER;
use super::MAX_CONN_COUNTER;
/// Accept TLS connections via `openssl` package.
///
/// `openssl` feature enables this `Acceptor` type.
pub struct Acceptor<T: AsyncRead + AsyncWrite> {
pub struct Acceptor {
acceptor: SslAcceptor,
io: PhantomData<T>,
}
impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
impl Acceptor {
/// Create OpenSSL based `Acceptor` service factory.
#[inline]
pub fn new(acceptor: SslAcceptor) -> Self {
Acceptor {
acceptor,
io: PhantomData,
}
Acceptor { acceptor }
}
}
impl<T: AsyncRead + AsyncWrite> Clone for Acceptor<T> {
impl Clone for Acceptor {
#[inline]
fn clone(&self) -> Self {
Self {
acceptor: self.acceptor.clone(),
io: PhantomData,
}
}
}
impl<T: AsyncRead + AsyncWrite + Unpin + 'static> ServiceFactory for Acceptor<T> {
type Request = T;
impl<T> ServiceFactory<T> for Acceptor
where
T: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Response = SslStream<T>;
type Error = HandshakeError<T>;
type Error = SslError;
type Config = ();
type Service = AcceptorService<T>;
type Service = AcceptorService;
type InitError = ();
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
MAX_CONN_COUNTER.with(|conns| {
ok(AcceptorService {
ready(Ok(AcceptorService {
acceptor: self.acceptor.clone(),
conns: conns.clone(),
io: PhantomData,
})
}))
})
}
}
pub struct AcceptorService<T> {
pub struct AcceptorService {
acceptor: SslAcceptor,
conns: Counter,
io: PhantomData<T>,
}
impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Service for AcceptorService<T> {
type Request = T;
impl<T> Service<T> for AcceptorService
where
T: AsyncRead + AsyncWrite + Unpin + 'static,
{
type Response = SslStream<T>;
type Error = HandshakeError<T>;
type Error = SslError;
type Future = AcceptorServiceResponse<T>;
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
@@ -82,15 +83,12 @@ impl<T: AsyncRead + AsyncWrite + Unpin + 'static> Service for AcceptorService<T>
}
}
fn call(&mut self, req: Self::Request) -> Self::Future {
let acc = self.acceptor.clone();
fn call(&mut self, io: T) -> Self::Future {
let ssl_ctx = self.acceptor.context();
let ssl = Ssl::new(ssl_ctx).expect("Provided SSL acceptor was invalid.");
AcceptorServiceResponse {
_guard: self.conns.get(),
fut: async move {
let acc = acc;
tokio_openssl::accept(&acc, req).await
}
.boxed_local(),
stream: Some(SslStream::new(ssl, io).unwrap()),
}
}
}
@@ -99,15 +97,15 @@ pub struct AcceptorServiceResponse<T>
where
T: AsyncRead + AsyncWrite,
{
fut: LocalBoxFuture<'static, Result<SslStream<T>, HandshakeError<T>>>,
stream: Option<SslStream<T>>,
_guard: CounterGuard,
}
impl<T: AsyncRead + AsyncWrite + Unpin> Future for AcceptorServiceResponse<T> {
type Output = Result<SslStream<T>, HandshakeError<T>>;
type Output = Result<SslStream<T>, SslError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let io = futures_util::ready!(Pin::new(&mut self.fut).poll(cx))?;
Poll::Ready(Ok(io))
ready!(Pin::new(self.stream.as_mut().unwrap()).poll_accept(cx))?;
Poll::Ready(Ok(self.stream.take().expect("SSL connect has resolved.")))
}
}

View File

@@ -1,6 +1,5 @@
use std::future::Future;
use std::io;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
@@ -8,74 +7,73 @@ use std::task::{Context, Poll};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::{Service, ServiceFactory};
use actix_utils::counter::{Counter, CounterGuard};
use futures_util::future::{ok, Ready};
use futures_util::future::{ready, Ready};
use tokio_rustls::{Accept, TlsAcceptor};
pub use rust_tls::{ServerConfig, Session};
pub use rustls::{ServerConfig, Session};
pub use tokio_rustls::server::TlsStream;
pub use webpki_roots::TLS_SERVER_ROOTS;
use crate::MAX_CONN_COUNTER;
use super::MAX_CONN_COUNTER;
/// Accept TLS connections via `rustls` package.
///
/// `rustls` feature enables this `Acceptor` type.
pub struct Acceptor<T> {
pub struct Acceptor {
config: Arc<ServerConfig>,
io: PhantomData<T>,
}
impl<T: AsyncRead + AsyncWrite> Acceptor<T> {
impl Acceptor {
/// Create Rustls based `Acceptor` service factory.
#[inline]
pub fn new(config: ServerConfig) -> Self {
Acceptor {
config: Arc::new(config),
io: PhantomData,
}
}
}
impl<T> Clone for Acceptor<T> {
impl Clone for Acceptor {
#[inline]
fn clone(&self) -> Self {
Self {
config: self.config.clone(),
io: PhantomData,
}
}
}
impl<T: AsyncRead + AsyncWrite + Unpin> ServiceFactory for Acceptor<T> {
type Request = T;
impl<T> ServiceFactory<T> for Acceptor
where
T: AsyncRead + AsyncWrite + Unpin,
{
type Response = TlsStream<T>;
type Error = io::Error;
type Service = AcceptorService<T>;
type Config = ();
type Service = AcceptorService;
type InitError = ();
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
MAX_CONN_COUNTER.with(|conns| {
ok(AcceptorService {
ready(Ok(AcceptorService {
acceptor: self.config.clone().into(),
conns: conns.clone(),
io: PhantomData,
})
}))
})
}
}
/// Rustls based `Acceptor` service
pub struct AcceptorService<T> {
pub struct AcceptorService {
acceptor: TlsAcceptor,
io: PhantomData<T>,
conns: Counter,
}
impl<T: AsyncRead + AsyncWrite + Unpin> Service for AcceptorService<T> {
type Request = T;
impl<T> Service<T> for AcceptorService
where
T: AsyncRead + AsyncWrite + Unpin,
{
type Response = TlsStream<T>;
type Error = io::Error;
type Future = AcceptorServiceFut<T>;
@@ -88,7 +86,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Service for AcceptorService<T> {
}
}
fn call(&mut self, req: Self::Request) -> Self::Future {
fn call(&mut self, req: T) -> Self::Future {
AcceptorServiceFut {
_guard: self.conns.get(),
fut: self.acceptor.accept(req),
@@ -104,16 +102,14 @@ where
_guard: CounterGuard,
}
impl<T: AsyncRead + AsyncWrite + Unpin> Future for AcceptorServiceFut<T> {
impl<T> Future for AcceptorServiceFut<T>
where
T: AsyncRead + AsyncWrite + Unpin,
{
type Output = Result<TlsStream<T>, io::Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let res = futures_util::ready!(Pin::new(&mut this.fut).poll(cx));
match res {
Ok(io) => Poll::Ready(Ok(io)),
Err(e) => Poll::Ready(Err(e)),
}
Pin::new(&mut this.fut).poll(cx)
}
}

View File

@@ -8,7 +8,8 @@ use std::task::{Context, Poll};
use actix_rt::net::TcpStream;
use actix_service::{Service, ServiceFactory};
use futures_util::future::{err, ok, BoxFuture, Either, FutureExt, Ready};
use futures_util::future::{ready, Ready};
use log::{error, trace};
use super::connect::{Address, Connect, Connection};
use super::error::ConnectError;
@@ -49,7 +50,7 @@ impl<T: Address> ServiceFactory<Connect<T>> for TcpConnectorFactory<T> {
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
ok(self.service())
ready(Ok(self.service()))
}
}
@@ -72,8 +73,7 @@ impl<T> Clone for TcpConnector<T> {
impl<T: Address> Service<Connect<T>> for TcpConnector<T> {
type Response = Connection<T, TcpStream>;
type Error = ConnectError;
#[allow(clippy::type_complexity)]
type Future = Either<TcpConnectorResponse<T>, Ready<Result<Self::Response, Self::Error>>>;
type Future = TcpConnectorResponse<T>;
actix_service::always_ready!();
@@ -82,21 +82,26 @@ impl<T: Address> Service<Connect<T>> for TcpConnector<T> {
let Connect { req, addr, .. } = req;
if let Some(addr) = addr {
Either::Left(TcpConnectorResponse::new(req, port, addr))
TcpConnectorResponse::new(req, port, addr)
} else {
error!("TCP connector: got unresolved address");
Either::Right(err(ConnectError::Unresolved))
TcpConnectorResponse::Error(Some(ConnectError::Unresolved))
}
}
}
type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
#[doc(hidden)]
/// TCP stream connector response future
pub struct TcpConnectorResponse<T> {
req: Option<T>,
port: u16,
addrs: Option<VecDeque<SocketAddr>>,
stream: Option<BoxFuture<'static, Result<TcpStream, io::Error>>>,
pub enum TcpConnectorResponse<T> {
Response {
req: Option<T>,
port: u16,
addrs: Option<VecDeque<SocketAddr>>,
stream: Option<LocalBoxFuture<'static, Result<TcpStream, io::Error>>>,
},
Error(Option<ConnectError>),
}
impl<T: Address> TcpConnectorResponse<T> {
@@ -112,13 +117,13 @@ impl<T: Address> TcpConnectorResponse<T> {
);
match addr {
either::Either::Left(addr) => TcpConnectorResponse {
either::Either::Left(addr) => TcpConnectorResponse::Response {
req: Some(req),
port,
addrs: None,
stream: Some(TcpStream::connect(addr).boxed()),
stream: Some(Box::pin(TcpStream::connect(addr))),
},
either::Either::Right(addrs) => TcpConnectorResponse {
either::Either::Right(addrs) => TcpConnectorResponse::Response {
req: Some(req),
port,
addrs: Some(addrs),
@@ -133,36 +138,43 @@ impl<T: Address> Future for TcpConnectorResponse<T> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
// connect
loop {
if let Some(new) = this.stream.as_mut() {
match new.as_mut().poll(cx) {
Poll::Ready(Ok(sock)) => {
let req = this.req.take().unwrap();
trace!(
"TCP connector - successfully connected to connecting to {:?} - {:?}",
req.host(), sock.peer_addr()
);
return Poll::Ready(Ok(Connection::new(sock, req)));
}
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(err)) => {
trace!(
"TCP connector - failed to connect to connecting to {:?} port: {}",
this.req.as_ref().unwrap().host(),
this.port,
);
if this.addrs.is_none() || this.addrs.as_ref().unwrap().is_empty() {
return Poll::Ready(Err(err.into()));
match this {
TcpConnectorResponse::Error(e) => Poll::Ready(Err(e.take().unwrap())),
// connect
TcpConnectorResponse::Response {
req,
port,
addrs,
stream,
} => loop {
if let Some(new) = stream.as_mut() {
match new.as_mut().poll(cx) {
Poll::Ready(Ok(sock)) => {
let req = req.take().unwrap();
trace!(
"TCP connector - successfully connected to connecting to {:?} - {:?}",
req.host(), sock.peer_addr()
);
return Poll::Ready(Ok(Connection::new(sock, req)));
}
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(err)) => {
trace!(
"TCP connector - failed to connect to connecting to {:?} port: {}",
req.as_ref().unwrap().host(),
port,
);
if addrs.is_none() || addrs.as_ref().unwrap().is_empty() {
return Poll::Ready(Err(err.into()));
}
}
}
}
}
// try to connect
let addr = this.addrs.as_mut().unwrap().pop_front().unwrap();
this.stream = Some(TcpStream::connect(addr).boxed());
// try to connect
let addr = addrs.as_mut().unwrap().pop_front().unwrap();
*stream = Some(Box::pin(TcpStream::connect(addr)));
},
}
}
}

View File

@@ -5,21 +5,12 @@
//! * `openssl` - enables TLS support via `openssl` crate
//! * `rustls` - enables TLS support via `rustls` crate
#![deny(rust_2018_idioms, nonstandard_style)]
#![recursion_limit = "128"]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
#[macro_use]
extern crate log;
mod connect;
mod connector;
mod error;
mod resolve;
mod service;
pub mod ssl;
#[cfg(feature = "uri")]
mod uri;
@@ -45,7 +36,7 @@ pub async fn start_resolver(
cfg: ResolverConfig,
opts: ResolverOpts,
) -> Result<AsyncResolver, ConnectError> {
Ok(AsyncResolver::tokio(cfg, opts).await?)
Ok(AsyncResolver::tokio(cfg, opts)?)
}
struct DefaultResolver(AsyncResolver);
@@ -62,7 +53,7 @@ pub(crate) async fn get_default_resolver() -> Result<AsyncResolver, ConnectError
}
};
let resolver = AsyncResolver::tokio(cfg, opts).await?;
let resolver = AsyncResolver::tokio(cfg, opts)?;
Arbiter::set_item(DefaultResolver(resolver.clone()));
Ok(resolver)

View File

@@ -6,12 +6,13 @@ use std::task::{Context, Poll};
use actix_service::{Service, ServiceFactory};
use futures_util::future::{ok, Either, Ready};
use log::trace;
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
use trust_dns_resolver::{error::ResolveError, lookup_ip::LookupIp};
use crate::connect::{Address, Connect};
use crate::error::ConnectError;
use crate::get_default_resolver;
use super::connect::{Address, Connect};
use super::error::ConnectError;
use super::get_default_resolver;
/// DNS Resolver Service factory
pub struct ResolverFactory<T> {

View File

@@ -8,10 +8,10 @@ use either::Either;
use futures_util::future::{ok, Ready};
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
use crate::connect::{Address, Connect, Connection};
use crate::connector::{TcpConnector, TcpConnectorFactory};
use crate::error::ConnectError;
use crate::resolve::{Resolver, ResolverFactory};
use super::connect::{Address, Connect, Connection};
use super::connector::{TcpConnector, TcpConnectorFactory};
use super::error::ConnectError;
use super::resolve::{Resolver, ResolverFactory};
pub struct ConnectServiceFactory<T> {
tcp: TcpConnectorFactory<T>,

View File

@@ -4,97 +4,83 @@ use std::pin::Pin;
use std::task::{Context, Poll};
use std::{fmt, io};
pub use open_ssl::ssl::{Error as SslError, SslConnector, SslMethod};
pub use tokio_openssl::{HandshakeError, SslStream};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_rt::net::TcpStream;
use actix_service::{Service, ServiceFactory};
use futures_util::future::{err, ok, Either, FutureExt, LocalBoxFuture, Ready};
use futures_util::{
future::{ready, Either, Ready},
ready,
};
use log::trace;
pub use openssl::ssl::{Error as SslError, HandshakeError, SslConnector, SslMethod};
pub use tokio_openssl::SslStream;
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
use crate::{
use crate::connect::{
Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection,
};
/// OpenSSL connector factory
pub struct OpensslConnector<T, U> {
pub struct OpensslConnector {
connector: SslConnector,
_t: PhantomData<(T, U)>,
}
impl<T, U> OpensslConnector<T, U> {
impl OpensslConnector {
pub fn new(connector: SslConnector) -> Self {
OpensslConnector {
connector,
_t: PhantomData,
}
OpensslConnector { connector }
}
}
impl<T, U> OpensslConnector<T, U>
where
T: Address + 'static,
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
{
pub fn service(connector: SslConnector) -> OpensslConnectorService<T, U> {
OpensslConnectorService {
connector,
_t: PhantomData,
}
impl OpensslConnector {
pub fn service(connector: SslConnector) -> OpensslConnectorService {
OpensslConnectorService { connector }
}
}
impl<T, U> Clone for OpensslConnector<T, U> {
impl Clone for OpensslConnector {
fn clone(&self) -> Self {
Self {
connector: self.connector.clone(),
_t: PhantomData,
}
}
}
impl<T, U> ServiceFactory for OpensslConnector<T, U>
impl<T, U> ServiceFactory<Connection<T, U>> for OpensslConnector
where
T: Address + 'static,
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
{
type Request = Connection<T, U>;
type Response = Connection<T, SslStream<U>>;
type Error = io::Error;
type Config = ();
type Service = OpensslConnectorService<T, U>;
type Service = OpensslConnectorService;
type InitError = ();
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
ok(OpensslConnectorService {
ready(Ok(OpensslConnectorService {
connector: self.connector.clone(),
_t: PhantomData,
})
}))
}
}
pub struct OpensslConnectorService<T, U> {
pub struct OpensslConnectorService {
connector: SslConnector,
_t: PhantomData<(T, U)>,
}
impl<T, U> Clone for OpensslConnectorService<T, U> {
impl Clone for OpensslConnectorService {
fn clone(&self) -> Self {
Self {
connector: self.connector.clone(),
_t: PhantomData,
}
}
}
impl<T, U> Service for OpensslConnectorService<T, U>
impl<T, U> Service<Connection<T, U>> for OpensslConnectorService
where
T: Address + 'static,
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
{
type Request = Connection<T, U>;
type Response = Connection<T, SslStream<U>>;
type Error = io::Error;
#[allow(clippy::type_complexity)]
@@ -108,19 +94,24 @@ where
let host = stream.host().to_string();
match self.connector.configure() {
Err(e) => Either::Right(err(io::Error::new(io::ErrorKind::Other, e))),
Ok(config) => Either::Left(ConnectAsyncExt {
fut: async move { tokio_openssl::connect(config, &host, io).await }
.boxed_local(),
stream: Some(stream),
_t: PhantomData,
}),
Err(e) => Either::Right(ready(Err(io::Error::new(io::ErrorKind::Other, e)))),
Ok(config) => {
let ssl = config
.into_ssl(&host)
.expect("SSL connect configuration was invalid.");
Either::Left(ConnectAsyncExt {
io: Some(SslStream::new(ssl, io).unwrap()),
stream: Some(stream),
_t: PhantomData,
})
}
}
}
}
pub struct ConnectAsyncExt<T, U> {
fut: LocalBoxFuture<'static, Result<SslStream<U>, HandshakeError<U>>>,
io: Option<SslStream<U>>,
stream: Option<Connection<T, ()>>,
_t: PhantomData<U>,
}
@@ -134,24 +125,23 @@ where
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
match Pin::new(&mut this.fut).poll(cx) {
Poll::Ready(Ok(stream)) => {
let s = this.stream.take().unwrap();
trace!("SSL Handshake success: {:?}", s.host());
Poll::Ready(Ok(s.replace(stream).1))
match ready!(Pin::new(this.io.as_mut().unwrap()).poll_connect(cx)) {
Ok(_) => {
let stream = this.stream.take().unwrap();
trace!("SSL Handshake success: {:?}", stream.host());
Poll::Ready(Ok(stream.replace(this.io.take().unwrap()).1))
}
Poll::Ready(Err(e)) => {
Err(e) => {
trace!("SSL Handshake error: {:?}", e);
Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
}
Poll::Pending => Poll::Pending,
}
}
}
pub struct OpensslConnectServiceFactory<T> {
tcp: ConnectServiceFactory<T>,
openssl: OpensslConnector<T, TcpStream>,
openssl: OpensslConnector,
}
impl<T> OpensslConnectServiceFactory<T> {
@@ -177,7 +167,6 @@ impl<T> OpensslConnectServiceFactory<T> {
tcp: self.tcp.service(),
openssl: OpensslConnectorService {
connector: self.openssl.connector.clone(),
_t: PhantomData,
},
}
}
@@ -192,8 +181,7 @@ impl<T> Clone for OpensslConnectServiceFactory<T> {
}
}
impl<T: Address + 'static> ServiceFactory for OpensslConnectServiceFactory<T> {
type Request = Connect<T>;
impl<T: Address + 'static> ServiceFactory<Connect<T>> for OpensslConnectServiceFactory<T> {
type Response = SslStream<TcpStream>;
type Error = ConnectError;
type Config = ();
@@ -202,18 +190,17 @@ impl<T: Address + 'static> ServiceFactory for OpensslConnectServiceFactory<T> {
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
ok(self.service())
ready(Ok(self.service()))
}
}
#[derive(Clone)]
pub struct OpensslConnectService<T> {
tcp: ConnectService<T>,
openssl: OpensslConnectorService<T, TcpStream>,
openssl: OpensslConnectorService,
}
impl<T: Address + 'static> Service for OpensslConnectService<T> {
type Request = Connect<T>;
impl<T: Address + 'static> Service<Connect<T>> for OpensslConnectService<T> {
type Response = SslStream<TcpStream>;
type Error = ConnectError;
type Future = OpensslConnectServiceResponse<T>;
@@ -230,9 +217,9 @@ impl<T: Address + 'static> Service for OpensslConnectService<T> {
}
pub struct OpensslConnectServiceResponse<T: Address + 'static> {
fut1: Option<<ConnectService<T> as Service>::Future>,
fut2: Option<<OpensslConnectorService<T, TcpStream> as Service>::Future>,
openssl: OpensslConnectorService<T, TcpStream>,
fut1: Option<<ConnectService<T> as Service<Connect<T>>>::Future>,
fut2: Option<<OpensslConnectorService as Service<Connection<T, TcpStream>>>::Future>,
openssl: OpensslConnectorService,
}
impl<T: Address> Future for OpensslConnectServiceResponse<T> {
@@ -240,7 +227,7 @@ impl<T: Address> Future for OpensslConnectServiceResponse<T> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(ref mut fut) = self.fut1 {
match futures_util::ready!(Pin::new(fut).poll(cx)) {
match ready!(Pin::new(fut).poll(cx)) {
Ok(res) => {
let _ = self.fut1.take();
self.fut2 = Some(self.openssl.call(res));
@@ -250,7 +237,7 @@ impl<T: Address> Future for OpensslConnectServiceResponse<T> {
}
if let Some(ref mut fut) = self.fut2 {
match futures_util::ready!(Pin::new(fut).poll(cx)) {
match ready!(Pin::new(fut).poll(cx)) {
Ok(connect) => Poll::Ready(Ok(connect.into_parts().0)),
Err(e) => Poll::Ready(Err(ConnectError::Io(io::Error::new(
io::ErrorKind::Other,

View File

@@ -1,97 +1,84 @@
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
pub use rust_tls::Session;
pub use rustls::Session;
pub use tokio_rustls::{client::TlsStream, rustls::ClientConfig};
use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::{Service, ServiceFactory};
use futures_util::future::{ok, Ready};
use futures_util::{
future::{ready, Ready},
ready,
};
use log::trace;
use tokio_rustls::{Connect, TlsConnector};
use webpki::DNSNameRef;
use crate::{Address, Connection};
use crate::connect::{Address, Connection};
/// Rustls connector factory
pub struct RustlsConnector<T, U> {
pub struct RustlsConnector {
connector: Arc<ClientConfig>,
_t: PhantomData<(T, U)>,
}
impl<T, U> RustlsConnector<T, U> {
impl RustlsConnector {
pub fn new(connector: Arc<ClientConfig>) -> Self {
RustlsConnector {
connector,
_t: PhantomData,
}
RustlsConnector { connector }
}
}
impl<T, U> RustlsConnector<T, U>
where
T: Address,
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
{
pub fn service(connector: Arc<ClientConfig>) -> RustlsConnectorService<T, U> {
RustlsConnectorService {
connector,
_t: PhantomData,
}
impl RustlsConnector {
pub fn service(connector: Arc<ClientConfig>) -> RustlsConnectorService {
RustlsConnectorService { connector }
}
}
impl<T, U> Clone for RustlsConnector<T, U> {
impl Clone for RustlsConnector {
fn clone(&self) -> Self {
Self {
connector: self.connector.clone(),
_t: PhantomData,
}
}
}
impl<T: Address, U> ServiceFactory for RustlsConnector<T, U>
impl<T: Address, U> ServiceFactory<Connection<T, U>> for RustlsConnector
where
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
{
type Request = Connection<T, U>;
type Response = Connection<T, TlsStream<U>>;
type Error = std::io::Error;
type Config = ();
type Service = RustlsConnectorService<T, U>;
type Service = RustlsConnectorService;
type InitError = ();
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
ok(RustlsConnectorService {
ready(Ok(RustlsConnectorService {
connector: self.connector.clone(),
_t: PhantomData,
})
}))
}
}
pub struct RustlsConnectorService<T, U> {
pub struct RustlsConnectorService {
connector: Arc<ClientConfig>,
_t: PhantomData<(T, U)>,
}
impl<T, U> Clone for RustlsConnectorService<T, U> {
impl Clone for RustlsConnectorService {
fn clone(&self) -> Self {
Self {
connector: self.connector.clone(),
_t: PhantomData,
}
}
}
impl<T: Address, U> Service for RustlsConnectorService<T, U>
impl<T, U> Service<Connection<T, U>> for RustlsConnectorService
where
T: Address,
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
{
type Request = Connection<T, U>;
type Response = Connection<T, TlsStream<U>>;
type Error = std::io::Error;
type Future = ConnectAsyncExt<T, U>;
@@ -115,20 +102,18 @@ pub struct ConnectAsyncExt<T, U> {
stream: Option<Connection<T, ()>>,
}
impl<T: Address, U> Future for ConnectAsyncExt<T, U>
impl<T, U> Future for ConnectAsyncExt<T, U>
where
T: Address,
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
{
type Output = Result<Connection<T, TlsStream<U>>, std::io::Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
Poll::Ready(
futures_util::ready!(Pin::new(&mut this.fut).poll(cx)).map(|stream| {
let s = this.stream.take().unwrap();
trace!("SSL Handshake success: {:?}", s.host());
s.replace(stream).1
}),
)
let stream = ready!(Pin::new(&mut this.fut).poll(cx))?;
let s = this.stream.take().unwrap();
trace!("SSL Handshake success: {:?}", s.host());
Poll::Ready(Ok(s.replace(stream).1))
}
}

View File

@@ -1,6 +1,6 @@
use http::Uri;
use crate::Address;
use super::Address;
impl Address for Uri {
fn host(&self) -> &str {

View File

@@ -1,46 +1,17 @@
//! TLS acceptor services for Actix ecosystem.
//!
//! ## Crate Features
//! * `openssl` - TLS acceptor using the `openssl` crate.
//! * `rustls` - TLS acceptor using the `rustls` crate.
//! * `nativetls` - TLS acceptor using the `native-tls` crate.
//! TLS acceptor and connector services for Actix ecosystem
#![deny(rust_2018_idioms, nonstandard_style)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use std::sync::atomic::{AtomicUsize, Ordering};
use actix_utils::counter::Counter;
#[cfg(feature = "native-tls")]
extern crate tls_native_tls as native_tls;
#[cfg(feature = "openssl")]
pub mod openssl;
extern crate tls_openssl as openssl;
#[cfg(feature = "rustls")]
pub mod rustls;
extern crate tls_rustls as rustls;
#[cfg(feature = "nativetls")]
pub mod nativetls;
pub(crate) static MAX_CONN: AtomicUsize = AtomicUsize::new(256);
thread_local! {
static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed));
}
/// Sets the maximum per-worker concurrent TLS connection limit.
///
/// All listeners will stop accepting connections when this limit is reached.
/// It can be used to regulate the global TLS CPU usage.
///
/// By default, the connection limit is 256.
pub fn max_concurrent_tls_connect(num: usize) {
MAX_CONN.store(num, Ordering::Relaxed);
}
/// TLS error combined with service error.
#[derive(Debug)]
pub enum TlsError<E1, E2> {
Tls(E1),
Service(E2),
}
#[cfg(feature = "accept")]
pub mod accept;
#[cfg(feature = "connect")]
pub mod connect;

View File

@@ -2,15 +2,18 @@ use std::io;
use actix_codec::{BytesCodec, Framed};
use actix_rt::net::TcpStream;
use actix_server::TestServer;
use actix_service::{fn_service, Service, ServiceFactory};
use actix_testing::TestServer;
use bytes::Bytes;
use futures_util::sink::SinkExt;
use actix_connect::resolver::{ResolverConfig, ResolverOpts};
use actix_connect::Connect;
use actix_tls::connect::{
self as actix_connect,
resolver::{ResolverConfig, ResolverOpts},
Connect,
};
#[cfg(feature = "openssl")]
#[cfg(all(feature = "connect", feature = "openssl"))]
#[actix_rt::test]
async fn test_string() {
let srv = TestServer::with(|| {

View File

@@ -16,11 +16,12 @@ name = "actix_tracing"
path = "src/lib.rs"
[dependencies]
actix-service = "1.0.4"
actix-service = "2.0.0-beta.1"
futures-util = { version = "0.3.4", default-features = false }
tracing = "0.1"
tracing-futures = "0.2"
[dev_dependencies]
actix-rt = "1.0"
slab = "0.4"
slab = "0.4"

36
bytestring/CHANGES.md Normal file
View File

@@ -0,0 +1,36 @@
# Changes
## Unreleased - 2020-xx-xx
## 1.0.0 - 2020-12-31
* Update `bytes` dependency to `1`.
* Add array and slice of `u8` impls of `TryFrom` up to 32 in length.
* Rename `get_ref` to `as_bytes` and rename `into_inner` to `into_bytes`.
* `ByteString::new` is now a `const fn`.
* Crate is now `#[no_std]` compatible.
## 0.1.5 - 2020-03-30
* Serde support
## 0.1.4 - 2020-01-14
* Fix `AsRef<str>` impl
## 0.1.3 - 2020-01-13
* Add `PartialEq<T: AsRef<str>>`, `AsRef<[u8]>` impls
## 0.1.2 - 2019-12-22
* Fix `new()` method
* Make `ByteString::from_static()` and `ByteString::from_bytes_unchecked()` methods const.
## 0.1.1 - 2019-12-07
* Fix hash impl
## 0.1.0 - 2019-12-07
* Initial release

View File

@@ -1,9 +1,13 @@
[package]
name = "bytestring"
version = "0.1.5"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "A UTF-8 encoded string with Bytes as a storage"
keywords = ["actix"]
version = "1.0.0"
authors = [
"Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>",
]
description = "An immutable UTF-8 encoded string using Bytes as storage"
keywords = ["string", "bytes", "utf8", "web", "actix"]
categories = ["no-std", "web-programming"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/bytestring/"
@@ -15,8 +19,9 @@ name = "bytestring"
path = "src/lib.rs"
[dependencies]
bytes = "0.5.3"
bytes = "1"
serde = { version = "1.0", optional = true }
[dev-dependencies]
serde_json = "1.0"
serde_json = "1.0"
siphasher = "0.3"

View File

@@ -1,37 +1,38 @@
//! A UTF-8 encoded read-only string using Bytes as storage.
#![no_std]
#![deny(rust_2018_idioms, nonstandard_style)]
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
use std::convert::TryFrom;
use std::{borrow, fmt, hash, ops, str};
extern crate alloc;
use alloc::{string::String, vec::Vec};
use core::{borrow, convert::TryFrom, fmt, hash, ops, str};
use bytes::Bytes;
/// A UTF-8 encoded string with [`Bytes`] as a storage.
///
/// [`Bytes`]: bytes::Bytes
#[derive(Clone, Eq, Ord, PartialOrd, Default)]
/// An immutable UTF-8 encoded string with [`Bytes`] as a storage.
#[derive(Clone, Default, Eq, PartialOrd, Ord)]
pub struct ByteString(Bytes);
impl ByteString {
/// Creates a new `ByteString`.
pub fn new() -> Self {
/// Creates a new empty `ByteString`.
pub const fn new() -> Self {
ByteString(Bytes::new())
}
/// Get a reference to the underlying bytes object.
pub fn get_ref(&self) -> &Bytes {
/// Get a reference to the underlying `Bytes` object.
pub fn as_bytes(&self) -> &Bytes {
&self.0
}
/// Unwraps this `ByteString`, returning the underlying bytes object.
pub fn into_inner(self) -> Bytes {
/// Unwraps this `ByteString` into the underlying `Bytes` object.
pub fn into_bytes(self) -> Bytes {
self.0
}
/// Creates a new `ByteString` from a static str.
/// Creates a new `ByteString` from a `&'static str`.
pub const fn from_static(src: &'static str) -> ByteString {
Self(Bytes::from_static(src.as_bytes()))
}
@@ -39,11 +40,10 @@ impl ByteString {
/// Creates a new `ByteString` from a Bytes.
///
/// # Safety
/// This function is unsafe because it does not check the bytes passed to it
/// are valid UTF-8. If this constraint is violated,
/// it may cause memory unsafety issues with future users of the `ByteString`,
/// as we assume that `ByteString`s are valid UTF-8.
/// However, the most likely issue is that the data gets corrupted.
/// This function is unsafe because it does not check the bytes passed to it are valid UTF-8.
/// If this constraint is violated, it may cause memory unsafety issues with future users of
/// the `ByteString`, as we assume that `ByteString`s are valid UTF-8. However, the most likely
/// issue is that the data gets corrupted.
pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
Self(src)
}
@@ -84,8 +84,10 @@ impl ops::Deref for ByteString {
#[inline]
fn deref(&self) -> &str {
let b = self.0.as_ref();
unsafe { str::from_utf8_unchecked(b) }
let bytes = self.0.as_ref();
// SAFETY:
// UTF-8 validity is guaranteed at during construction.
unsafe { str::from_utf8_unchecked(bytes) }
}
}
@@ -96,21 +98,24 @@ impl borrow::Borrow<str> for ByteString {
}
impl From<String> for ByteString {
#[inline]
fn from(value: String) -> Self {
Self(Bytes::from(value))
}
}
impl<'a> From<&'a str> for ByteString {
fn from(value: &'a str) -> Self {
impl From<&str> for ByteString {
#[inline]
fn from(value: &str) -> Self {
Self(Bytes::copy_from_slice(value.as_ref()))
}
}
impl<'a> TryFrom<&'a [u8]> for ByteString {
impl TryFrom<&[u8]> for ByteString {
type Error = str::Utf8Error;
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
#[inline]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let _ = str::from_utf8(value)?;
Ok(ByteString(Bytes::copy_from_slice(value)))
}
@@ -119,15 +124,17 @@ impl<'a> TryFrom<&'a [u8]> for ByteString {
impl TryFrom<Vec<u8>> for ByteString {
type Error = str::Utf8Error;
#[inline]
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
let _ = str::from_utf8(value.as_ref())?;
Ok(ByteString(Bytes::from(value)))
let buf = String::from_utf8(value).map_err(|err| err.utf8_error())?;
Ok(ByteString(Bytes::from(buf)))
}
}
impl TryFrom<Bytes> for ByteString {
type Error = str::Utf8Error;
#[inline]
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
let _ = str::from_utf8(value.as_ref())?;
Ok(ByteString(value))
@@ -137,8 +144,9 @@ impl TryFrom<Bytes> for ByteString {
impl TryFrom<bytes::BytesMut> for ByteString {
type Error = str::Utf8Error;
#[inline]
fn try_from(value: bytes::BytesMut) -> Result<Self, Self::Error> {
let _ = str::from_utf8(value.as_ref())?;
let _ = str::from_utf8(&value)?;
Ok(ByteString(value.freeze()))
}
}
@@ -146,10 +154,20 @@ impl TryFrom<bytes::BytesMut> for ByteString {
macro_rules! array_impls {
($($len:expr)+) => {
$(
impl<'a> TryFrom<&'a [u8; $len]> for ByteString {
impl TryFrom<[u8; $len]> for ByteString {
type Error = str::Utf8Error;
fn try_from(value: &'a [u8; $len]) -> Result<Self, Self::Error> {
#[inline]
fn try_from(value: [u8; $len]) -> Result<Self, Self::Error> {
ByteString::try_from(&value[..])
}
}
impl TryFrom<&[u8; $len]> for ByteString {
type Error = str::Utf8Error;
#[inline]
fn try_from(value: &[u8; $len]) -> Result<Self, Self::Error> {
ByteString::try_from(&value[..])
}
}
@@ -157,7 +175,7 @@ macro_rules! array_impls {
}
}
array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32);
impl fmt::Debug for ByteString {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -173,6 +191,8 @@ impl fmt::Display for ByteString {
#[cfg(feature = "serde")]
mod serde {
use alloc::string::String;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
@@ -201,16 +221,19 @@ mod serde {
#[cfg(test)]
mod test {
use alloc::borrow::ToOwned;
use core::hash::{Hash, Hasher};
use siphasher::sip::SipHasher;
use super::*;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
#[test]
fn test_partial_eq() {
let s: ByteString = ByteString::from_static("test");
assert_eq!(s, "test");
assert_eq!(s, *"test");
assert_eq!(s, "test".to_string());
assert_eq!(s, "test".to_owned());
}
#[test]
@@ -220,10 +243,10 @@ mod test {
#[test]
fn test_hash() {
let mut hasher1 = DefaultHasher::default();
let mut hasher1 = SipHasher::default();
"str".hash(&mut hasher1);
let mut hasher2 = DefaultHasher::default();
let mut hasher2 = SipHasher::default();
let s = ByteString::from_static("str");
s.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());
@@ -231,7 +254,7 @@ mod test {
#[test]
fn test_from_string() {
let s: ByteString = "hello".to_string().into();
let s: ByteString = "hello".to_owned().into();
assert_eq!(&s, "hello");
let t: &str = s.as_ref();
assert_eq!(t, "hello");
@@ -249,17 +272,25 @@ mod test {
}
#[test]
fn test_try_from_rbytes() {
fn test_try_from_slice() {
let _ = ByteString::try_from(b"nice bytes").unwrap();
}
#[test]
fn test_try_from_array() {
assert_eq!(
ByteString::try_from([b'h', b'i']).unwrap(),
ByteString::from_static("hi")
);
}
#[test]
fn test_try_from_bytes() {
let _ = ByteString::try_from(Bytes::from_static(b"nice bytes")).unwrap();
}
#[test]
fn test_try_from_bytesmut() {
fn test_try_from_bytes_mut() {
let _ = ByteString::try_from(bytes::BytesMut::from(&b"nice bytes"[..])).unwrap();
}

View File

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

View File

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

View File

@@ -1,27 +0,0 @@
# Changes
## [0.1.5] - 2020-03-30
* Serde support
## [0.1.4] - 2020-01-14
* Fix `AsRef<str>` impl
## [0.1.3] - 2020-01-13
* Add `PartialEq<T: AsRef<str>>`, `AsRef<[u8]>` impls
## [0.1.2] - 2019-12-22
* Fix `new()` method
* Make `ByteString::from_static()` and `ByteString::from_bytes_unchecked()` methods const.
## [0.1.1] - 2019-12-07
* Fix hash impl
## [0.1.0] - 2019-12-07
* Initial release

View File

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

View File

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