diff --git a/Cargo.toml b/Cargo.toml index d46b6283..533fbc17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "actix-codec", - "actix-connect", "actix-rt", "actix-macros", "actix-service", @@ -16,16 +15,15 @@ members = [ ] [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-rt = { path = "actix-rt" } actix-macros = { path = "actix-macros" } actix-server = { path = "actix-server" } -actix-service = { git = "https://github.com/actix/actix-net.git", rev = "ba44ea7d0bafaf5fccb9a34003d503e1910943ee" } +actix-service = { path = "actix-service" } actix-testing = { path = "actix-testing" } 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-utils = { path = "actix-utils" } actix-router = { path = "router" } bytestring = { path = "string" } diff --git a/actix-connect/CHANGES.md b/actix-connect/CHANGES.md deleted file mode 100644 index 6f18b5b4..00000000 --- a/actix-connect/CHANGES.md +++ /dev/null @@ -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 diff --git a/actix-connect/Cargo.toml b/actix-connect/Cargo.toml deleted file mode 100644 index 233195c5..00000000 --- a/actix-connect/Cargo.toml +++ /dev/null @@ -1,58 +0,0 @@ -[package] -name = "actix-connect" -version = "2.0.0" -authors = ["Nikolay Kim "] -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" diff --git a/actix-connect/LICENSE-APACHE b/actix-connect/LICENSE-APACHE deleted file mode 120000 index 965b606f..00000000 --- a/actix-connect/LICENSE-APACHE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-APACHE \ No newline at end of file diff --git a/actix-connect/LICENSE-MIT b/actix-connect/LICENSE-MIT deleted file mode 120000 index 76219eb7..00000000 --- a/actix-connect/LICENSE-MIT +++ /dev/null @@ -1 +0,0 @@ -../LICENSE-MIT \ No newline at end of file diff --git a/actix-connect/tests/test_connect.rs b/actix-connect/tests/test_connect.rs deleted file mode 100644 index 21d78d2c..00000000 --- a/actix-connect/tests/test_connect.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::io; - -use actix_codec::{BytesCodec, Framed}; -use actix_rt::net::TcpStream; -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; - -#[cfg(feature = "openssl")] -#[actix_rt::test] -async fn test_string() { - let srv = TestServer::with(|| { - fn_service(|io: TcpStream| async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - }) - }); - - let mut conn = actix_connect::default_connector(); - let addr = format!("localhost:{}", srv.port()); - let con = conn.call(addr.into()).await.unwrap(); - assert_eq!(con.peer_addr().unwrap(), srv.addr()); -} - -#[cfg(feature = "rustls")] -#[actix_rt::test] -async fn test_rustls_string() { - let srv = TestServer::with(|| { - fn_service(|io: TcpStream| async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - }) - }); - - let mut conn = actix_connect::default_connector(); - let addr = format!("localhost:{}", srv.port()); - let con = conn.call(addr.into()).await.unwrap(); - assert_eq!(con.peer_addr().unwrap(), srv.addr()); -} - -#[actix_rt::test] -async fn test_static_str() { - let srv = TestServer::with(|| { - fn_service(|io: TcpStream| async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - }) - }); - - let resolver = actix_connect::start_default_resolver().await.unwrap(); - let mut conn = actix_connect::new_connector(resolver.clone()); - - let con = conn.call(Connect::with("10", srv.addr())).await.unwrap(); - assert_eq!(con.peer_addr().unwrap(), srv.addr()); - - let connect = Connect::new(srv.host().to_owned()); - let mut conn = actix_connect::new_connector(resolver); - let con = conn.call(connect).await; - assert!(con.is_err()); -} - -#[actix_rt::test] -async fn test_new_service() { - let srv = TestServer::with(|| { - fn_service(|io: TcpStream| async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - }) - }); - - let resolver = - actix_connect::start_resolver(ResolverConfig::default(), ResolverOpts::default()) - .await - .unwrap(); - - let factory = actix_connect::new_connector_factory(resolver); - - let mut conn = factory.new_service(()).await.unwrap(); - let con = conn.call(Connect::with("10", srv.addr())).await.unwrap(); - assert_eq!(con.peer_addr().unwrap(), srv.addr()); -} - -#[cfg(all(feature = "openssl", feature = "uri"))] -#[actix_rt::test] -async fn test_openssl_uri() { - use std::convert::TryFrom; - - let srv = TestServer::with(|| { - fn_service(|io: TcpStream| async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - }) - }); - - let mut conn = actix_connect::default_connector(); - let addr = http::Uri::try_from(format!("https://localhost:{}", srv.port())).unwrap(); - let con = conn.call(addr.into()).await.unwrap(); - assert_eq!(con.peer_addr().unwrap(), srv.addr()); -} - -#[cfg(all(feature = "rustls", feature = "uri"))] -#[actix_rt::test] -async fn test_rustls_uri() { - use std::convert::TryFrom; - - let srv = TestServer::with(|| { - fn_service(|io: TcpStream| async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - }) - }); - - let mut conn = actix_connect::default_connector(); - let addr = http::Uri::try_from(format!("https://localhost:{}", srv.port())).unwrap(); - let con = conn.call(addr.into()).await.unwrap(); - assert_eq!(con.peer_addr().unwrap(), srv.addr()); -} diff --git a/actix-tls/CHANGES.md b/actix-tls/CHANGES.md index 592b96b0..9f03bfeb 100644 --- a/actix-tls/CHANGES.md +++ b/actix-tls/CHANGES.md @@ -1,6 +1,11 @@ # Changes ## Unreleased - 2020-xx-xx +* 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]: https://github.com/actix/actix-net/pull/238 ## 2.0.0 - 2020-09-03 diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index dcd5978a..de2d859f 100644 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -2,8 +2,8 @@ name = "actix-tls" version = "2.0.0" authors = ["Nikolay Kim "] -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", "http"] [lib] name = "actix_tls" @@ -20,45 +20,59 @@ path = "src/lib.rs" [[example]] name = "basic" -required-features = ["rustls"] +required-features = ["accept", "rustls"] [features] -default = [] +default = ["accept", "connect", "http"] -# openssl -openssl = ["open-ssl", "tokio-openssl"] +# enable acceptor services +accept = [] -# rustls -rustls = ["rust-tls", "webpki", "webpki-roots", "tokio-rustls"] +# enable connector services +connect = [] -# 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"] [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.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 } +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" +actix-testing = "2.0.0-beta.1" +bytes = "1" +log = "0.4" +env_logger = "0.8" diff --git a/actix-tls/examples/basic.rs b/actix-tls/examples/basic.rs index cd706958..3f4cdb24 100644 --- a/actix-tls/examples/basic.rs +++ b/actix-tls/examples/basic.rs @@ -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, }; diff --git a/actix-tls/src/accept/mod.rs b/actix-tls/src/accept/mod.rs new file mode 100644 index 00000000..8b1fe47c --- /dev/null +++ b/actix-tls/src/accept/mod.rs @@ -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 { + Tls(E1), + Service(E2), +} diff --git a/actix-tls/src/nativetls.rs b/actix-tls/src/accept/nativetls.rs similarity index 87% rename from actix-tls/src/nativetls.rs rename to actix-tls/src/accept/nativetls.rs index fa66bff6..12d23855 100644 --- a/actix-tls/src/nativetls.rs +++ b/actix-tls/src/accept/nativetls.rs @@ -7,13 +7,13 @@ use actix_utils::counter::Counter; use futures_util::future::{self, FutureExt, LocalBoxFuture, TryFutureExt}; 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. +/// `native-tls` feature enables this `Acceptor` type. pub struct Acceptor { acceptor: TlsAcceptor, io: PhantomData, @@ -43,11 +43,10 @@ impl Clone for Acceptor { } } -impl ServiceFactory for Acceptor +impl ServiceFactory for Acceptor where T: AsyncRead + AsyncWrite + Unpin + 'static, { - type Request = T; type Response = TlsStream; type Error = Error; type Service = NativeTlsAcceptorService; @@ -83,11 +82,10 @@ impl Clone for NativeTlsAcceptorService { } } -impl Service for NativeTlsAcceptorService +impl Service for NativeTlsAcceptorService where T: AsyncRead + AsyncWrite + Unpin + 'static, { - type Request = T; type Response = TlsStream; type Error = Error; type Future = LocalBoxFuture<'static, Result, Error>>; @@ -100,10 +98,10 @@ 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 } + async move { this.acceptor.accept(io).await } .map_ok(move |io| { // Required to preserve `CounterGuard` until `Self::Future` is completely resolved. let _ = guard; diff --git a/actix-tls/src/openssl.rs b/actix-tls/src/accept/openssl.rs similarity index 69% rename from actix-tls/src/openssl.rs rename to actix-tls/src/accept/openssl.rs index 46dc10de..44877b24 100644 --- a/actix-tls/src/openssl.rs +++ b/actix-tls/src/accept/openssl.rs @@ -6,12 +6,17 @@ 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::{ok, 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. /// @@ -42,10 +47,12 @@ impl Clone for Acceptor { } } -impl ServiceFactory for Acceptor { - type Request = T; +impl ServiceFactory for Acceptor +where + T: AsyncRead + AsyncWrite + Unpin + 'static, +{ type Response = SslStream; - type Error = HandshakeError; + type Error = SslError; type Config = (); type Service = AcceptorService; type InitError = (); @@ -68,10 +75,12 @@ pub struct AcceptorService { io: PhantomData, } -impl Service for AcceptorService { - type Request = T; +impl Service for AcceptorService +where + T: AsyncRead + AsyncWrite + Unpin + 'static, +{ type Response = SslStream; - type Error = HandshakeError; + type Error = SslError; type Future = AcceptorServiceResponse; fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll> { @@ -82,15 +91,14 @@ impl Service for AcceptorService } } - fn call(&mut self, req: Self::Request) -> Self::Future { + fn call(&mut self, io: T) -> Self::Future { let acc = self.acceptor.clone(); + let ssl_ctx = acc.into_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 +107,15 @@ pub struct AcceptorServiceResponse where T: AsyncRead + AsyncWrite, { - fut: LocalBoxFuture<'static, Result, HandshakeError>>, + stream: Option>, _guard: CounterGuard, } impl Future for AcceptorServiceResponse { - type Output = Result, HandshakeError>; + type Output = Result, SslError>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - 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."))) } } diff --git a/actix-tls/src/rustls.rs b/actix-tls/src/accept/rustls.rs similarity index 85% rename from actix-tls/src/rustls.rs rename to actix-tls/src/accept/rustls.rs index 3c3c60bf..1c40757e 100644 --- a/actix-tls/src/rustls.rs +++ b/actix-tls/src/accept/rustls.rs @@ -11,11 +11,11 @@ use actix_utils::counter::{Counter, CounterGuard}; use futures_util::future::{ok, 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. /// @@ -25,7 +25,10 @@ pub struct Acceptor { io: PhantomData, } -impl Acceptor { +impl Acceptor +where + T: AsyncRead + AsyncWrite, +{ /// Create Rustls based `Acceptor` service factory. #[inline] pub fn new(config: ServerConfig) -> Self { @@ -46,8 +49,10 @@ impl Clone for Acceptor { } } -impl ServiceFactory for Acceptor { - type Request = T; +impl ServiceFactory for Acceptor +where + T: AsyncRead + AsyncWrite + Unpin, +{ type Response = TlsStream; type Error = io::Error; type Service = AcceptorService; @@ -74,8 +79,10 @@ pub struct AcceptorService { conns: Counter, } -impl Service for AcceptorService { - type Request = T; +impl Service for AcceptorService +where + T: AsyncRead + AsyncWrite + Unpin, +{ type Response = TlsStream; type Error = io::Error; type Future = AcceptorServiceFut; @@ -88,7 +95,7 @@ impl Service for AcceptorService { } } - 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,7 +111,10 @@ where _guard: CounterGuard, } -impl Future for AcceptorServiceFut { +impl Future for AcceptorServiceFut +where + T: AsyncRead + AsyncWrite + Unpin, +{ type Output = Result, io::Error>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { diff --git a/actix-connect/src/connect.rs b/actix-tls/src/connect/connect.rs similarity index 100% rename from actix-connect/src/connect.rs rename to actix-tls/src/connect/connect.rs diff --git a/actix-connect/src/connector.rs b/actix-tls/src/connect/connector.rs similarity index 99% rename from actix-connect/src/connector.rs rename to actix-tls/src/connect/connector.rs index d3ef9813..c7a31e0a 100644 --- a/actix-connect/src/connector.rs +++ b/actix-tls/src/connect/connector.rs @@ -9,6 +9,7 @@ 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 log::{error, trace}; use super::connect::{Address, Connect, Connection}; use super::error::ConnectError; diff --git a/actix-connect/src/error.rs b/actix-tls/src/connect/error.rs similarity index 100% rename from actix-connect/src/error.rs rename to actix-tls/src/connect/error.rs diff --git a/actix-connect/src/lib.rs b/actix-tls/src/connect/mod.rs similarity index 93% rename from actix-connect/src/lib.rs rename to actix-tls/src/connect/mod.rs index d2111d41..753cfc33 100644 --- a/actix-connect/src/lib.rs +++ b/actix-tls/src/connect/mod.rs @@ -5,22 +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; use actix_rt::{net::TcpStream, Arbiter}; diff --git a/actix-connect/src/resolve.rs b/actix-tls/src/connect/resolve.rs similarity index 97% rename from actix-connect/src/resolve.rs rename to actix-tls/src/connect/resolve.rs index 2c75cc0d..61535faa 100644 --- a/actix-connect/src/resolve.rs +++ b/actix-tls/src/connect/resolve.rs @@ -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 { diff --git a/actix-connect/src/service.rs b/actix-tls/src/connect/service.rs similarity index 97% rename from actix-connect/src/service.rs rename to actix-tls/src/connect/service.rs index b942d230..59fe20cc 100644 --- a/actix-connect/src/service.rs +++ b/actix-tls/src/connect/service.rs @@ -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 { tcp: TcpConnectorFactory, diff --git a/actix-connect/src/ssl/mod.rs b/actix-tls/src/connect/ssl/mod.rs similarity index 100% rename from actix-connect/src/ssl/mod.rs rename to actix-tls/src/connect/ssl/mod.rs diff --git a/actix-connect/src/ssl/openssl.rs b/actix-tls/src/connect/ssl/openssl.rs similarity index 80% rename from actix-connect/src/ssl/openssl.rs rename to actix-tls/src/connect/ssl/openssl.rs index a9bcc3c7..f249717d 100644 --- a/actix-connect/src/ssl/openssl.rs +++ b/actix-tls/src/connect/ssl/openssl.rs @@ -4,16 +4,19 @@ 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::{err, ok, 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, }; @@ -54,12 +57,11 @@ impl Clone for OpensslConnector { } } -impl ServiceFactory for OpensslConnector +impl ServiceFactory> for OpensslConnector where T: Address + 'static, U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static, { - type Request = Connection; type Response = Connection>; type Error = io::Error; type Config = (); @@ -89,12 +91,11 @@ impl Clone for OpensslConnectorService { } } -impl Service for OpensslConnectorService +impl Service> for OpensslConnectorService where T: Address + 'static, U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static, { - type Request = Connection; type Response = Connection>; type Error = io::Error; #[allow(clippy::type_complexity)] @@ -109,18 +110,23 @@ where 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, - }), + 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 { - fut: LocalBoxFuture<'static, Result, HandshakeError>>, + io: Option>, stream: Option>, _t: PhantomData, } @@ -134,17 +140,16 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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, } } } @@ -192,8 +197,7 @@ impl Clone for OpensslConnectServiceFactory { } } -impl ServiceFactory for OpensslConnectServiceFactory { - type Request = Connect; +impl ServiceFactory> for OpensslConnectServiceFactory { type Response = SslStream; type Error = ConnectError; type Config = (); @@ -212,8 +216,7 @@ pub struct OpensslConnectService { openssl: OpensslConnectorService, } -impl Service for OpensslConnectService { - type Request = Connect; +impl Service> for OpensslConnectService { type Response = SslStream; type Error = ConnectError; type Future = OpensslConnectServiceResponse; @@ -230,8 +233,10 @@ impl Service for OpensslConnectService { } pub struct OpensslConnectServiceResponse { - fut1: Option< as Service>::Future>, - fut2: Option< as Service>::Future>, + fut1: Option< as Service>>::Future>, + fut2: Option< + as Service>>::Future, + >, openssl: OpensslConnectorService, } @@ -240,7 +245,7 @@ impl Future for OpensslConnectServiceResponse { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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 +255,7 @@ impl Future for OpensslConnectServiceResponse { } 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, diff --git a/actix-connect/src/ssl/rustls.rs b/actix-tls/src/connect/ssl/rustls.rs similarity index 93% rename from actix-connect/src/ssl/rustls.rs rename to actix-tls/src/connect/ssl/rustls.rs index 984fbe49..f5259280 100644 --- a/actix-connect/src/ssl/rustls.rs +++ b/actix-tls/src/connect/ssl/rustls.rs @@ -5,16 +5,17 @@ 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 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 { @@ -53,11 +54,10 @@ impl Clone for RustlsConnector { } } -impl ServiceFactory for RustlsConnector +impl ServiceFactory> for RustlsConnector where U: AsyncRead + AsyncWrite + Unpin + fmt::Debug, { - type Request = Connection; type Response = Connection>; type Error = std::io::Error; type Config = (); @@ -87,11 +87,10 @@ impl Clone for RustlsConnectorService { } } -impl Service for RustlsConnectorService +impl Service> for RustlsConnectorService where U: AsyncRead + AsyncWrite + Unpin + fmt::Debug, { - type Request = Connection; type Response = Connection>; type Error = std::io::Error; type Future = ConnectAsyncExt; diff --git a/actix-connect/src/uri.rs b/actix-tls/src/connect/uri.rs similarity index 97% rename from actix-connect/src/uri.rs rename to actix-tls/src/connect/uri.rs index 5f5f15de..b208a8b3 100644 --- a/actix-connect/src/uri.rs +++ b/actix-tls/src/connect/uri.rs @@ -1,6 +1,6 @@ use http::Uri; -use crate::Address; +use super::Address; impl Address for Uri { fn host(&self) -> &str { diff --git a/actix-tls/src/lib.rs b/actix-tls/src/lib.rs index 8cc18046..1fa08b6b 100644 --- a/actix-tls/src/lib.rs +++ b/actix-tls/src/lib.rs @@ -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 { - Tls(E1), - Service(E2), -} +#[cfg(feature = "accept")] +pub mod accept; +#[cfg(feature = "connect")] +pub mod connect;