From b1eb57ac4f4dce05dd043ab9fca871af8f84f164 Mon Sep 17 00:00:00 2001 From: Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> Date: Sat, 3 Feb 2024 16:20:07 +0000 Subject: [PATCH 01/14] Update Cargo.toml (#3276) --- awc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 14009fb4f..5c09400a0 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -72,7 +72,7 @@ cfg-if = "1" derive_more = "0.99.5" futures-core = { version = "0.3.17", default-features = false, features = ["alloc"] } futures-util = { version = "0.3.17", default-features = false, features = ["alloc", "sink"] } -h2 = "0.3.17" +h2 = "0.3.24" http = "0.2.7" itoa = "1" log =" 0.4" From 2125aca2c5e0bba99172ce1a00f72531a58cee2a Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sat, 3 Feb 2024 23:55:01 +0000 Subject: [PATCH 02/14] Rustls v0.22 support (#3275) --- .cargo/config.toml | 4 +- .github/workflows/ci-post-merge.yml | 23 ++-- .github/workflows/ci.yml | 23 ++-- actix-files/src/lib.rs | 1 + actix-http/CHANGES.md | 2 + actix-http/Cargo.toml | 31 +++-- actix-http/examples/tls_rustls.rs | 20 ++-- actix-http/examples/ws.rs | 21 ++-- actix-http/src/h1/service.rs | 65 +++++++++- actix-http/src/h2/service.rs | 55 ++++++++- actix-http/src/lib.rs | 7 +- actix-http/src/service.rs | 124 ++++++++++++++++++-- actix-http/tests/test_rustls.rs | 63 +++++----- actix-test/CHANGES.md | 2 + actix-test/Cargo.toml | 3 + actix-test/src/lib.rs | 83 +++++++++++-- actix-web/CHANGES.md | 3 + actix-web/Cargo.toml | 19 ++- actix-web/src/server.rs | 85 ++++++++++++++ actix-web/tests/test_server.rs | 2 +- awc/CHANGES.md | 3 + awc/Cargo.toml | 30 +++-- awc/src/client/connector.rs | 176 ++++++++++++++++++++-------- awc/tests/test_rustls_client.rs | 70 +++++++---- 24 files changed, 719 insertions(+), 196 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 931b20b2c..350a924de 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,6 @@ [alias] -lint = "clippy --workspace --tests --examples --bins -- -Dclippy::todo" -lint-all = "clippy --workspace --all-features --tests --examples --bins -- -Dclippy::todo" +lint = "clippy --workspace --all-targets -- -Dclippy::todo" +lint-all = "clippy --workspace --all-features --all-targets -- -Dclippy::todo" # lib checking ci-check-min = "hack --workspace check --no-default-features" diff --git a/.github/workflows/ci-post-merge.yml b/.github/workflows/ci-post-merge.yml index d2f952ec7..de9b30a59 100644 --- a/.github/workflows/ci-post-merge.yml +++ b/.github/workflows/ci-post-merge.yml @@ -32,22 +32,22 @@ jobs: - name: Install OpenSSL if: matrix.target.os == 'windows-latest' - run: choco install openssl -y --forcex64 --no-progress - - name: Set OpenSSL dir in env - if: matrix.target.os == 'windows-latest' + shell: bash run: | - echo 'OPENSSL_DIR=C:\Program Files\OpenSSL-Win64' | Out-File -FilePath $env:GITHUB_ENV -Append - echo 'OPENSSL_DIR=C:\Program Files\OpenSSL' | Out-File -FilePath $env:GITHUB_ENV -Append + set -e + choco install openssl --version=1.1.1.2100 -y --no-progress + echo 'OPENSSL_DIR=C:\Program Files\OpenSSL' >> $GITHUB_ENV + echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV - name: Install Rust (${{ matrix.version.name }}) uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 with: toolchain: ${{ matrix.version.version }} - - name: Install cargo-hack + - name: Install cargo-hack and cargo-ci-cache-clean uses: taiki-e/install-action@v2.26.8 with: - tool: cargo-hack + tool: cargo-hack,cargo-ci-cache-clean - name: check minimal run: cargo ci-check-min @@ -57,10 +57,12 @@ jobs: - name: tests timeout-minutes: 60 + shell: bash run: | + set -e cargo test --lib --tests -p=actix-router --all-features cargo test --lib --tests -p=actix-http --all-features - cargo test --lib --tests -p=actix-web --features=rustls-0_20,rustls-0_21,openssl -- --skip=test_reading_deflate_encoding_large_random_rustls + cargo test --lib --tests -p=actix-web --features=rustls-0_20,rustls-0_21,rustls-0_22,openssl -- --skip=test_reading_deflate_encoding_large_random_rustls cargo test --lib --tests -p=actix-web-codegen --all-features cargo test --lib --tests -p=awc --all-features cargo test --lib --tests -p=actix-http-test --all-features @@ -69,11 +71,6 @@ jobs: cargo test --lib --tests -p=actix-multipart --all-features cargo test --lib --tests -p=actix-web-actors --all-features - - name: Install cargo-ci-cache-clean - uses: taiki-e/install-action@v2.26.8 - with: - tool: cargo-ci-cache-clean - - name: CI cache clean run: cargo-ci-cache-clean diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d2f5bb1c..79c581b81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,22 +37,22 @@ jobs: - name: Install OpenSSL if: matrix.target.os == 'windows-latest' - run: choco install openssl -y --forcex64 --no-progress --version=3.2.1 - - name: Set OpenSSL dir in env - if: matrix.target.os == 'windows-latest' + shell: bash run: | - echo 'OPENSSL_DIR=C:\Program Files\OpenSSL-Win64' | Out-File -FilePath $env:GITHUB_ENV -Append - echo 'OPENSSL_DIR=C:\Program Files\OpenSSL' | Out-File -FilePath $env:GITHUB_ENV -Append + set -e + choco install openssl --version=1.1.1.2100 -y --no-progress + echo 'OPENSSL_DIR=C:\Program Files\OpenSSL' >> $GITHUB_ENV + echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV - name: Install Rust (${{ matrix.version.name }}) uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 with: toolchain: ${{ matrix.version.version }} - - name: Install cargo-hack + - name: Install cargo-hack and cargo-ci-cache-clean uses: taiki-e/install-action@v2.26.8 with: - tool: cargo-hack + tool: cargo-hack,cargo-ci-cache-clean - name: workaround MSRV issues if: matrix.version.name == 'msrv' @@ -71,10 +71,12 @@ jobs: - name: tests timeout-minutes: 60 + shell: bash run: | + set -e cargo test --lib --tests -p=actix-router --all-features cargo test --lib --tests -p=actix-http --all-features - cargo test --lib --tests -p=actix-web --features=rustls-0_20,rustls-0_21,openssl -- --skip=test_reading_deflate_encoding_large_random_rustls + cargo test --lib --tests -p=actix-web --features=rustls-0_20,rustls-0_21,rustls-0_22,openssl -- --skip=test_reading_deflate_encoding_large_random_rustls cargo test --lib --tests -p=actix-web-codegen --all-features cargo test --lib --tests -p=awc --all-features cargo test --lib --tests -p=actix-http-test --all-features @@ -83,11 +85,6 @@ jobs: cargo test --lib --tests -p=actix-multipart --all-features cargo test --lib --tests -p=actix-web-actors --all-features - - name: Install cargo-ci-cache-clean - uses: taiki-e/install-action@v2.26.8 - with: - tool: cargo-ci-cache-clean - - name: CI cache clean run: cargo-ci-cache-clean diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs index 5b1f14eed..8381519aa 100644 --- a/actix-files/src/lib.rs +++ b/actix-files/src/lib.rs @@ -568,6 +568,7 @@ mod tests { assert_eq!(bytes, data); } + #[cfg(not(target_os = "windows"))] #[actix_rt::test] async fn test_static_files_with_special_characters() { // Create the file we want to test against ad-hoc. We can't check it in as otherwise diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index 3ce06442e..aca2a2573 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -4,6 +4,8 @@ ### Added +- Add `rustls-0_22` crate feature. +- Add `{h1::H1Service, h2::H2Service, HttpService}::rustls_0_22()` and `HttpService::rustls_0_22_with_config()` service constructors. - Implement `From<&HeaderMap>` for `http::HeaderMap`. ## 3.5.1 diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index e7d50c313..3a3000169 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -20,8 +20,18 @@ edition.workspace = true rust-version.workspace = true [package.metadata.docs.rs] -# features that docs.rs will build with -features = ["http2", "ws", "openssl", "rustls-0_20", "rustls-0_21", "compress-brotli", "compress-gzip", "compress-zstd"] +rustdoc-args = ["--cfg", "docsrs"] +features = [ + "http2", + "ws", + "openssl", + "rustls-0_20", + "rustls-0_21", + "rustls-0_22", + "compress-brotli", + "compress-gzip", + "compress-zstd", +] [lib] name = "actix_http" @@ -53,6 +63,9 @@ rustls-0_20 = ["actix-tls/accept", "actix-tls/rustls-0_20"] # TLS via Rustls v0.21 rustls-0_21 = ["actix-tls/accept", "actix-tls/rustls-0_21"] +# TLS via Rustls v0.22 +rustls-0_22 = ["actix-tls/accept", "actix-tls/rustls-0_22"] + # Compression codecs compress-brotli = ["__compress", "brotli"] compress-gzip = ["__compress", "flate2"] @@ -98,7 +111,7 @@ rand = { version = "0.8", optional = true } sha1 = { version = "0.10", optional = true } # openssl/rustls -actix-tls = { version = "3.1", default-features = false, optional = true } +actix-tls = { version = "3.3", default-features = false, optional = true } # compress-* brotli = { version = "3.3.3", optional = true } @@ -108,7 +121,7 @@ zstd = { version = "0.13", optional = true } [dev-dependencies] actix-http-test = { version = "3", features = ["openssl"] } actix-server = "2" -actix-tls = { version = "3.1", features = ["openssl"] } +actix-tls = { version = "3.3", features = ["openssl", "rustls-0_22-webpki-roots"] } actix-web = "4" async-stream = "0.3" @@ -117,24 +130,24 @@ env_logger = "0.10" futures-util = { version = "0.3.17", default-features = false, features = ["alloc"] } memchr = "2.4" once_cell = "1.9" -rcgen = "0.11" +rcgen = "0.12" regex = "1.3" rustversion = "1" -rustls-pemfile = "1" +rustls-pemfile = "2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" static_assertions = "1" tls-openssl = { package = "openssl", version = "0.10.55" } -tls-rustls_021 = { package = "rustls", version = "0.21" } +tls-rustls_022 = { package = "rustls", version = "0.22" } tokio = { version = "1.24.2", features = ["net", "rt", "macros"] } [[example]] name = "ws" -required-features = ["ws", "rustls-0_21"] +required-features = ["ws", "rustls-0_22"] [[example]] name = "tls_rustls" -required-features = ["http2", "rustls-0_21"] +required-features = ["http2", "rustls-0_22"] [[bench]] name = "response-body-compression" diff --git a/actix-http/examples/tls_rustls.rs b/actix-http/examples/tls_rustls.rs index fbb55c6a4..47ff061cd 100644 --- a/actix-http/examples/tls_rustls.rs +++ b/actix-http/examples/tls_rustls.rs @@ -12,7 +12,7 @@ //! Protocol: HTTP/1.1 //! ``` -extern crate tls_rustls_021 as rustls; +extern crate tls_rustls_022 as rustls; use std::io; @@ -36,7 +36,7 @@ async fn main() -> io::Result<()> { ); ok::<_, Error>(Response::ok().set_body(body)) }) - .rustls_021(rustls_config()) + .rustls_0_22(rustls_config()) })? .run() .await @@ -51,16 +51,18 @@ fn rustls_config() -> rustls::ServerConfig { let key_file = &mut io::BufReader::new(key_file.as_bytes()); let cert_chain = rustls_pemfile::certs(cert_file) - .unwrap() - .into_iter() - .map(rustls::Certificate) - .collect(); - let mut keys = rustls_pemfile::pkcs8_private_keys(key_file).unwrap(); + .collect::, _>>() + .unwrap(); + let mut keys = rustls_pemfile::pkcs8_private_keys(key_file) + .collect::, _>>() + .unwrap(); let mut config = rustls::ServerConfig::builder() - .with_safe_defaults() .with_no_client_auth() - .with_single_cert(cert_chain, rustls::PrivateKey(keys.remove(0))) + .with_single_cert( + cert_chain, + rustls::pki_types::PrivateKeyDer::Pkcs8(keys.remove(0)), + ) .unwrap(); const H1_ALPN: &[u8] = b"http/1.1"; diff --git a/actix-http/examples/ws.rs b/actix-http/examples/ws.rs index 241175ae2..55085fd73 100644 --- a/actix-http/examples/ws.rs +++ b/actix-http/examples/ws.rs @@ -1,7 +1,7 @@ //! Sets up a WebSocket server over TCP and TLS. //! Sends a heartbeat message every 4 seconds but does not respond to any incoming frames. -extern crate tls_rustls_021 as rustls; +extern crate tls_rustls_022 as rustls; use std::{ io, @@ -30,7 +30,7 @@ async fn main() -> io::Result<()> { .bind("tls", ("127.0.0.1", 8443), || { HttpService::build() .finish(handler) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) })? .run() .await @@ -85,7 +85,6 @@ impl Stream for Heartbeat { fn tls_config() -> rustls::ServerConfig { use std::io::BufReader; - use rustls::{Certificate, PrivateKey}; use rustls_pemfile::{certs, pkcs8_private_keys}; let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); @@ -95,17 +94,17 @@ fn tls_config() -> rustls::ServerConfig { let cert_file = &mut BufReader::new(cert_file.as_bytes()); let key_file = &mut BufReader::new(key_file.as_bytes()); - let cert_chain = certs(cert_file) - .unwrap() - .into_iter() - .map(Certificate) - .collect(); - let mut keys = pkcs8_private_keys(key_file).unwrap(); + let cert_chain = certs(cert_file).collect::, _>>().unwrap(); + let mut keys = pkcs8_private_keys(key_file) + .collect::, _>>() + .unwrap(); let mut config = rustls::ServerConfig::builder() - .with_safe_defaults() .with_no_client_auth() - .with_single_cert(cert_chain, PrivateKey(keys.remove(0))) + .with_single_cert( + cert_chain, + rustls::pki_types::PrivateKeyDer::Pkcs8(keys.remove(0)), + ) .unwrap(); config.alpn_protocols.push(b"http/1.1".to_vec()); diff --git a/actix-http/src/h1/service.rs b/actix-http/src/h1/service.rs index 3b27e3db5..64eb39c82 100644 --- a/actix-http/src/h1/service.rs +++ b/actix-http/src/h1/service.rs @@ -153,7 +153,7 @@ mod openssl { } #[cfg(feature = "rustls-0_20")] -mod rustls_020 { +mod rustls_0_20 { use std::io; use actix_service::ServiceFactoryExt as _; @@ -214,7 +214,7 @@ mod rustls_020 { } #[cfg(feature = "rustls-0_21")] -mod rustls_021 { +mod rustls_0_21 { use std::io; use actix_service::ServiceFactoryExt as _; @@ -274,6 +274,67 @@ mod rustls_021 { } } +#[cfg(feature = "rustls-0_22")] +mod rustls_0_22 { + use std::io; + + use actix_service::ServiceFactoryExt as _; + use actix_tls::accept::{ + rustls_0_22::{reexports::ServerConfig, Acceptor, TlsStream}, + TlsError, + }; + + use super::*; + + impl H1Service, S, B, X, U> + where + S: ServiceFactory, + S::Future: 'static, + S::Error: Into>, + S::InitError: fmt::Debug, + S::Response: Into>, + + B: MessageBody, + + X: ServiceFactory, + X::Future: 'static, + X::Error: Into>, + X::InitError: fmt::Debug, + + U: ServiceFactory< + (Request, Framed, Codec>), + Config = (), + Response = (), + >, + U::Future: 'static, + U::Error: fmt::Display + Into>, + U::InitError: fmt::Debug, + { + /// Create Rustls v0.22 based service. + pub fn rustls_0_22( + self, + config: ServerConfig, + ) -> impl ServiceFactory< + TcpStream, + Config = (), + Response = (), + Error = TlsError, + InitError = (), + > { + Acceptor::new(config) + .map_init_err(|_| { + unreachable!("TLS acceptor service factory does not error on init") + }) + .map_err(TlsError::into_service_error) + .map(|io: TlsStream| { + let peer_addr = io.get_ref().0.peer_addr().ok(); + (io, peer_addr) + }) + .and_then(self.map_err(TlsError::Service)) + } + } +} + impl H1Service where S: ServiceFactory, diff --git a/actix-http/src/h2/service.rs b/actix-http/src/h2/service.rs index 0ae7ea682..d50ffc4e3 100644 --- a/actix-http/src/h2/service.rs +++ b/actix-http/src/h2/service.rs @@ -141,7 +141,7 @@ mod openssl { } #[cfg(feature = "rustls-0_20")] -mod rustls_020 { +mod rustls_0_20 { use std::io; use actix_service::ServiceFactoryExt as _; @@ -192,7 +192,7 @@ mod rustls_020 { } #[cfg(feature = "rustls-0_21")] -mod rustls_021 { +mod rustls_0_21 { use std::io; use actix_service::ServiceFactoryExt as _; @@ -242,6 +242,57 @@ mod rustls_021 { } } +#[cfg(feature = "rustls-0_22")] +mod rustls_0_22 { + use std::io; + + use actix_service::ServiceFactoryExt as _; + use actix_tls::accept::{ + rustls_0_22::{reexports::ServerConfig, Acceptor, TlsStream}, + TlsError, + }; + + use super::*; + + impl H2Service, S, B> + where + S: ServiceFactory, + S::Future: 'static, + S::Error: Into> + 'static, + S::Response: Into> + 'static, + >::Future: 'static, + + B: MessageBody + 'static, + { + /// Create Rustls v0.22 based service. + pub fn rustls_0_22( + self, + mut config: ServerConfig, + ) -> impl ServiceFactory< + TcpStream, + Config = (), + Response = (), + Error = TlsError, + InitError = S::InitError, + > { + let mut protos = vec![b"h2".to_vec()]; + protos.extend_from_slice(&config.alpn_protocols); + config.alpn_protocols = protos; + + Acceptor::new(config) + .map_init_err(|_| { + unreachable!("TLS acceptor service factory does not error on init") + }) + .map_err(TlsError::into_service_error) + .map(|io: TlsStream| { + let peer_addr = io.get_ref().0.peer_addr().ok(); + (io, peer_addr) + }) + .and_then(self.map_err(TlsError::Service)) + } + } +} + impl ServiceFactory<(T, Option)> for H2Service where T: AsyncRead + AsyncWrite + Unpin + 'static, diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index 888c3e06f..cb82ced00 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -58,7 +58,12 @@ pub mod ws; #[allow(deprecated)] pub use self::payload::PayloadStream; -#[cfg(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21"))] +#[cfg(any( + feature = "openssl", + feature = "rustls-0_20", + feature = "rustls-0_21", + feature = "rustls-0_22", +))] pub use self::service::TlsAcceptorConfig; pub use self::{ builder::HttpServiceBuilder, diff --git a/actix-http/src/service.rs b/actix-http/src/service.rs index fb38ba636..e24387182 100644 --- a/actix-http/src/service.rs +++ b/actix-http/src/service.rs @@ -241,13 +241,23 @@ where } /// Configuration options used when accepting TLS connection. -#[cfg(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21"))] +#[cfg(any( + feature = "openssl", + feature = "rustls-0_20", + feature = "rustls-0_21", + feature = "rustls-0_22", +))] #[derive(Debug, Default)] pub struct TlsAcceptorConfig { pub(crate) handshake_timeout: Option, } -#[cfg(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21"))] +#[cfg(any( + feature = "openssl", + feature = "rustls-0_20", + feature = "rustls-0_21", + feature = "rustls-0_22", +))] impl TlsAcceptorConfig { /// Set TLS handshake timeout duration. pub fn handshake_timeout(self, dur: std::time::Duration) -> Self { @@ -353,12 +363,12 @@ mod openssl { } #[cfg(feature = "rustls-0_20")] -mod rustls_020 { +mod rustls_0_20 { use std::io; use actix_service::ServiceFactoryExt as _; use actix_tls::accept::{ - rustls::{reexports::ServerConfig, Acceptor, TlsStream}, + rustls_0_20::{reexports::ServerConfig, Acceptor, TlsStream}, TlsError, }; @@ -389,7 +399,7 @@ mod rustls_020 { U::Error: fmt::Display + Into>, U::InitError: fmt::Debug, { - /// Create Rustls based service. + /// Create Rustls v0.20 based service. pub fn rustls( self, config: ServerConfig, @@ -403,7 +413,7 @@ mod rustls_020 { self.rustls_with_config(config, TlsAcceptorConfig::default()) } - /// Create Rustls based service with custom TLS acceptor configuration. + /// Create Rustls v0.20 based service with custom TLS acceptor configuration. pub fn rustls_with_config( self, mut config: ServerConfig, @@ -449,7 +459,7 @@ mod rustls_020 { } #[cfg(feature = "rustls-0_21")] -mod rustls_021 { +mod rustls_0_21 { use std::io; use actix_service::ServiceFactoryExt as _; @@ -485,7 +495,7 @@ mod rustls_021 { U::Error: fmt::Display + Into>, U::InitError: fmt::Debug, { - /// Create Rustls based service. + /// Create Rustls v0.21 based service. pub fn rustls_021( self, config: ServerConfig, @@ -499,7 +509,7 @@ mod rustls_021 { self.rustls_021_with_config(config, TlsAcceptorConfig::default()) } - /// Create Rustls based service with custom TLS acceptor configuration. + /// Create Rustls v0.21 based service with custom TLS acceptor configuration. pub fn rustls_021_with_config( self, mut config: ServerConfig, @@ -544,6 +554,102 @@ mod rustls_021 { } } +#[cfg(feature = "rustls-0_22")] +mod rustls_0_22 { + use std::io; + + use actix_service::ServiceFactoryExt as _; + use actix_tls::accept::{ + rustls_0_22::{reexports::ServerConfig, Acceptor, TlsStream}, + TlsError, + }; + + use super::*; + + impl HttpService, S, B, X, U> + where + S: ServiceFactory, + S::Future: 'static, + S::Error: Into> + 'static, + S::InitError: fmt::Debug, + S::Response: Into> + 'static, + >::Future: 'static, + + B: MessageBody + 'static, + + X: ServiceFactory, + X::Future: 'static, + X::Error: Into>, + X::InitError: fmt::Debug, + + U: ServiceFactory< + (Request, Framed, h1::Codec>), + Config = (), + Response = (), + >, + U::Future: 'static, + U::Error: fmt::Display + Into>, + U::InitError: fmt::Debug, + { + /// Create Rustls v0.22 based service. + pub fn rustls_0_22( + self, + config: ServerConfig, + ) -> impl ServiceFactory< + TcpStream, + Config = (), + Response = (), + Error = TlsError, + InitError = (), + > { + self.rustls_0_22_with_config(config, TlsAcceptorConfig::default()) + } + + /// Create Rustls v0.22 based service with custom TLS acceptor configuration. + pub fn rustls_0_22_with_config( + self, + mut config: ServerConfig, + tls_acceptor_config: TlsAcceptorConfig, + ) -> impl ServiceFactory< + TcpStream, + Config = (), + Response = (), + Error = TlsError, + InitError = (), + > { + let mut protos = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; + protos.extend_from_slice(&config.alpn_protocols); + config.alpn_protocols = protos; + + let mut acceptor = Acceptor::new(config); + + if let Some(handshake_timeout) = tls_acceptor_config.handshake_timeout { + acceptor.set_handshake_timeout(handshake_timeout); + } + + acceptor + .map_init_err(|_| { + unreachable!("TLS acceptor service factory does not error on init") + }) + .map_err(TlsError::into_service_error) + .and_then(|io: TlsStream| async { + let proto = if let Some(protos) = io.get_ref().1.alpn_protocol() { + if protos.windows(2).any(|window| window == b"h2") { + Protocol::Http2 + } else { + Protocol::Http1 + } + } else { + Protocol::Http1 + }; + let peer_addr = io.get_ref().0.peer_addr().ok(); + Ok((io, proto, peer_addr)) + }) + .and_then(self.map_err(TlsError::Service)) + } + } +} + impl ServiceFactory<(T, Protocol, Option)> for HttpService where diff --git a/actix-http/tests/test_rustls.rs b/actix-http/tests/test_rustls.rs index c94e579e5..08b3a249b 100644 --- a/actix-http/tests/test_rustls.rs +++ b/actix-http/tests/test_rustls.rs @@ -1,6 +1,6 @@ -#![cfg(feature = "rustls-0_21")] +#![cfg(feature = "rustls-0_22")] -extern crate tls_rustls_021 as rustls; +extern crate tls_rustls_022 as rustls; use std::{ convert::Infallible, @@ -20,13 +20,13 @@ use actix_http::{ use actix_http_test::test_server; use actix_rt::pin; use actix_service::{fn_factory_with_config, fn_service}; -use actix_tls::connect::rustls_0_21::webpki_roots_cert_store; +use actix_tls::connect::rustls_0_22::webpki_roots_cert_store; use actix_utils::future::{err, ok, poll_fn}; use bytes::{Bytes, BytesMut}; use derive_more::{Display, Error}; use futures_core::{ready, Stream}; use futures_util::stream::once; -use rustls::{Certificate, PrivateKey, ServerConfig as RustlsServerConfig, ServerName}; +use rustls::{pki_types::ServerName, ServerConfig as RustlsServerConfig}; use rustls_pemfile::{certs, pkcs8_private_keys}; async fn load_body(stream: S) -> Result @@ -59,17 +59,17 @@ fn tls_config() -> RustlsServerConfig { let cert_file = &mut BufReader::new(cert_file.as_bytes()); let key_file = &mut BufReader::new(key_file.as_bytes()); - let cert_chain = certs(cert_file) - .unwrap() - .into_iter() - .map(Certificate) - .collect(); - let mut keys = pkcs8_private_keys(key_file).unwrap(); + let cert_chain = certs(cert_file).collect::, _>>().unwrap(); + let mut keys = pkcs8_private_keys(key_file) + .collect::, _>>() + .unwrap(); let mut config = RustlsServerConfig::builder() - .with_safe_defaults() .with_no_client_auth() - .with_single_cert(cert_chain, PrivateKey(keys.remove(0))) + .with_single_cert( + cert_chain, + rustls::pki_types::PrivateKeyDer::Pkcs8(keys.remove(0)), + ) .unwrap(); config.alpn_protocols.push(HTTP1_1_ALPN_PROTOCOL.to_vec()); @@ -83,7 +83,6 @@ pub fn get_negotiated_alpn_protocol( client_alpn_protocol: &[u8], ) -> Option> { let mut config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(webpki_roots_cert_store()) .with_no_client_auth(); @@ -109,7 +108,7 @@ async fn h1() -> io::Result<()> { let srv = test_server(move || { HttpService::build() .h1(|_| ok::<_, Error>(Response::ok())) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -123,7 +122,7 @@ async fn h2() -> io::Result<()> { let srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, Error>(Response::ok())) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -141,7 +140,7 @@ async fn h1_1() -> io::Result<()> { assert_eq!(req.version(), Version::HTTP_11); ok::<_, Error>(Response::ok()) }) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -159,7 +158,7 @@ async fn h2_1() -> io::Result<()> { assert_eq!(req.version(), Version::HTTP_2); ok::<_, Error>(Response::ok()) }) - .rustls_021_with_config( + .rustls_0_22_with_config( tls_config(), TlsAcceptorConfig::default().handshake_timeout(Duration::from_secs(5)), ) @@ -180,7 +179,7 @@ async fn h2_body1() -> io::Result<()> { let body = load_body(req.take_payload()).await?; Ok::<_, Error>(Response::ok().set_body(body)) }) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -206,7 +205,7 @@ async fn h2_content_length() { ]; ok::<_, Infallible>(Response::new(statuses[indx])) }) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -278,7 +277,7 @@ async fn h2_headers() { } ok::<_, Infallible>(config.body(data.clone())) }) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -317,7 +316,7 @@ async fn h2_body2() { let mut srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, Infallible>(Response::ok().set_body(STR))) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -334,7 +333,7 @@ async fn h2_head_empty() { let mut srv = test_server(move || { HttpService::build() .finish(|_| ok::<_, Infallible>(Response::ok().set_body(STR))) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -360,7 +359,7 @@ async fn h2_head_binary() { let mut srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, Infallible>(Response::ok().set_body(STR))) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -385,7 +384,7 @@ async fn h2_head_binary2() { let srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, Infallible>(Response::ok().set_body(STR))) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -411,7 +410,7 @@ async fn h2_body_length() { Response::ok().set_body(SizedStream::new(STR.len() as u64, body)), ) }) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -435,7 +434,7 @@ async fn h2_body_chunked_explicit() { .body(BodyStream::new(body)), ) }) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -464,7 +463,7 @@ async fn h2_response_http_error_handling() { ) })) })) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -494,7 +493,7 @@ async fn h2_service_error() { let mut srv = test_server(move || { HttpService::build() .h2(|_| err::, _>(BadRequest)) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -511,7 +510,7 @@ async fn h1_service_error() { let mut srv = test_server(move || { HttpService::build() .h1(|_| err::, _>(BadRequest)) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) }) .await; @@ -534,7 +533,7 @@ async fn alpn_h1() -> io::Result<()> { config.alpn_protocols.push(CUSTOM_ALPN_PROTOCOL.to_vec()); HttpService::build() .h1(|_| ok::<_, Error>(Response::ok())) - .rustls_021(config) + .rustls_0_22(config) }) .await; @@ -556,7 +555,7 @@ async fn alpn_h2() -> io::Result<()> { config.alpn_protocols.push(CUSTOM_ALPN_PROTOCOL.to_vec()); HttpService::build() .h2(|_| ok::<_, Error>(Response::ok())) - .rustls_021(config) + .rustls_0_22(config) }) .await; @@ -582,7 +581,7 @@ async fn alpn_h2_1() -> io::Result<()> { config.alpn_protocols.push(CUSTOM_ALPN_PROTOCOL.to_vec()); HttpService::build() .finish(|_| ok::<_, Error>(Response::ok())) - .rustls_021(config) + .rustls_0_22(config) }) .await; diff --git a/actix-test/CHANGES.md b/actix-test/CHANGES.md index a3ca7fe10..bdacc8b2d 100644 --- a/actix-test/CHANGES.md +++ b/actix-test/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +- Add `TestServerConfig::rustls_0_22()` method for Rustls v0.22 support behind new `rustls-0_22` crate feature. + ## 0.1.2 - Add `TestServerConfig::rustls_021()` method for Rustls v0.21 support behind new `rustls-0_21` crate feature. diff --git a/actix-test/Cargo.toml b/actix-test/Cargo.toml index 46d65abdc..d5be25384 100644 --- a/actix-test/Cargo.toml +++ b/actix-test/Cargo.toml @@ -27,6 +27,8 @@ rustls = ["rustls-0_20"] rustls-0_20 = ["tls-rustls-0_20", "actix-http/rustls-0_20", "awc/rustls-0_20"] # TLS via Rustls v0.21 rustls-0_21 = ["tls-rustls-0_21", "actix-http/rustls-0_21", "awc/rustls-0_21"] +# TLS via Rustls v0.22 +rustls-0_22 = ["tls-rustls-0_22", "actix-http/rustls-0_22", "awc/rustls-0_22-webpki-roots"] # TLS via OpenSSL openssl = ["tls-openssl", "actix-http/openssl", "awc/openssl"] @@ -50,4 +52,5 @@ serde_urlencoded = "0.7" tls-openssl = { package = "openssl", version = "0.10.55", optional = true } tls-rustls-0_20 = { package = "rustls", version = "0.20", optional = true } tls-rustls-0_21 = { package = "rustls", version = "0.21", optional = true } +tls-rustls-0_22 = { package = "rustls", version = "0.22", optional = true } tokio = { version = "1.24.2", features = ["sync"] } diff --git a/actix-test/src/lib.rs b/actix-test/src/lib.rs index e570bb266..b7aeddad2 100644 --- a/actix-test/src/lib.rs +++ b/actix-test/src/lib.rs @@ -143,6 +143,8 @@ where StreamType::Rustls020(_) => true, #[cfg(feature = "rustls-0_21")] StreamType::Rustls021(_) => true, + #[cfg(feature = "rustls-0_22")] + StreamType::Rustls022(_) => true, }; // run server in separate orphaned thread @@ -327,6 +329,48 @@ where .rustls_021(config.clone()) }), }, + #[cfg(feature = "rustls-0_22")] + StreamType::Rustls022(config) => match cfg.tp { + HttpVer::Http1 => builder.listen("test", tcp, move || { + let app_cfg = + AppConfig::__priv_test_new(false, local_addr.to_string(), local_addr); + + let fac = factory() + .into_factory() + .map_err(|err| err.into().error_response()); + + HttpService::build() + .client_request_timeout(timeout) + .h1(map_config(fac, move |_| app_cfg.clone())) + .rustls_0_22(config.clone()) + }), + HttpVer::Http2 => builder.listen("test", tcp, move || { + let app_cfg = + AppConfig::__priv_test_new(false, local_addr.to_string(), local_addr); + + let fac = factory() + .into_factory() + .map_err(|err| err.into().error_response()); + + HttpService::build() + .client_request_timeout(timeout) + .h2(map_config(fac, move |_| app_cfg.clone())) + .rustls_0_22(config.clone()) + }), + HttpVer::Both => builder.listen("test", tcp, move || { + let app_cfg = + AppConfig::__priv_test_new(false, local_addr.to_string(), local_addr); + + let fac = factory() + .into_factory() + .map_err(|err| err.into().error_response()); + + HttpService::build() + .client_request_timeout(timeout) + .finish(map_config(fac, move |_| app_cfg.clone())) + .rustls_0_22(config.clone()) + }), + }, } .expect("test server could not be created"); @@ -401,6 +445,8 @@ enum StreamType { Rustls020(tls_rustls_0_20::ServerConfig), #[cfg(feature = "rustls-0_21")] Rustls021(tls_rustls_0_21::ServerConfig), + #[cfg(feature = "rustls-0_22")] + Rustls022(tls_rustls_0_22::ServerConfig), } /// Create default test server config. @@ -424,7 +470,7 @@ impl Default for TestServerConfig { } impl TestServerConfig { - /// Create default server configuration + /// Constructs default server configuration. pub(crate) fn new() -> TestServerConfig { TestServerConfig { tp: HttpVer::Both, @@ -435,40 +481,63 @@ impl TestServerConfig { } } - /// Accept HTTP/1.1 only. + /// Accepts HTTP/1.1 only. pub fn h1(mut self) -> Self { self.tp = HttpVer::Http1; self } - /// Accept HTTP/2 only. + /// Accepts HTTP/2 only. pub fn h2(mut self) -> Self { self.tp = HttpVer::Http2; self } - /// Accept secure connections via OpenSSL. + /// Accepts secure connections via OpenSSL. #[cfg(feature = "openssl")] pub fn openssl(mut self, acceptor: openssl::ssl::SslAcceptor) -> Self { self.stream = StreamType::Openssl(acceptor); self } - /// Accept secure connections via Rustls. + #[doc(hidden)] + #[deprecated(note = "Renamed to `rustls_0_20()`.")] #[cfg(feature = "rustls-0_20")] pub fn rustls(mut self, config: tls_rustls_0_20::ServerConfig) -> Self { self.stream = StreamType::Rustls020(config); self } - /// Accept secure connections via Rustls. + /// Accepts secure connections via Rustls v0.20. + #[cfg(feature = "rustls-0_20")] + pub fn rustls_0_20(mut self, config: tls_rustls_0_20::ServerConfig) -> Self { + self.stream = StreamType::Rustls020(config); + self + } + + #[doc(hidden)] + #[deprecated(note = "Renamed to `rustls_0_21()`.")] #[cfg(feature = "rustls-0_21")] pub fn rustls_021(mut self, config: tls_rustls_0_21::ServerConfig) -> Self { self.stream = StreamType::Rustls021(config); self } - /// Set client timeout for first request. + /// Accepts secure connections via Rustls v0.21. + #[cfg(feature = "rustls-0_21")] + pub fn rustls_0_21(mut self, config: tls_rustls_0_21::ServerConfig) -> Self { + self.stream = StreamType::Rustls021(config); + self + } + + /// Accepts secure connections via Rustls v0.22. + #[cfg(feature = "rustls-0_22")] + pub fn rustls_0_22(mut self, config: tls_rustls_0_22::ServerConfig) -> Self { + self.stream = StreamType::Rustls022(config); + self + } + + /// Sets client timeout for first request. pub fn client_request_timeout(mut self, dur: Duration) -> Self { self.client_request_timeout = dur; self diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md index 674c834ad..072cdc012 100644 --- a/actix-web/CHANGES.md +++ b/actix-web/CHANGES.md @@ -2,6 +2,9 @@ ## Unreleased +- Add `rustls-0_22` crate feature. +- Add `HttpServer::{bind_rustls_0_22, listen_rustls_0_22}()` builder methods. + ## 4.4.1 ### Changed diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index d1fc9c916..37299721f 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -20,9 +20,20 @@ edition.workspace = true rust-version.workspace = true [package.metadata.docs.rs] -# features that docs.rs will build with -features = ["macros", "openssl", "rustls-0_20", "rustls-0_21", "compress-brotli", "compress-gzip", "compress-zstd", "cookies", "secure-cookies"] rustdoc-args = ["--cfg", "docsrs"] +features = [ + "macros", + "openssl", + "rustls-0_20", + "rustls-0_21", + "rustls-0_22", + "compress-brotli", + "compress-gzip", + "compress-zstd", + "cookies", + "secure-cookies", +] + [lib] name = "actix_web" @@ -58,6 +69,8 @@ rustls = ["rustls-0_20"] rustls-0_20 = ["http2", "actix-http/rustls-0_20", "actix-tls/accept", "actix-tls/rustls-0_20"] # TLS via Rustls v0.21 rustls-0_21 = ["http2", "actix-http/rustls-0_21", "actix-tls/accept", "actix-tls/rustls-0_21"] +# TLS via Rustls v0.22 +rustls-0_22 = ["http2", "actix-http/rustls-0_22", "actix-tls/accept", "actix-tls/rustls-0_22"] # Internal (PRIVATE!) features used to aid testing and checking feature status. # Don't rely on these whatsoever. They may disappear at anytime. @@ -73,7 +86,7 @@ actix-rt = { version = "2.6", default-features = false } actix-server = "2" actix-service = "2" actix-utils = "3" -actix-tls = { version = "3.1", default-features = false, optional = true } +actix-tls = { version = "3.3", default-features = false, optional = true } actix-http = { version = "3.5", features = ["ws"] } actix-router = "0.5" diff --git a/actix-web/src/server.rs b/actix-web/src/server.rs index 2cc00cb9f..193a7cce9 100644 --- a/actix-web/src/server.rs +++ b/actix-web/src/server.rs @@ -442,6 +442,25 @@ where Ok(self) } + /// Resolves socket address(es) and binds server to created listener(s) for TLS connections + /// using Rustls v0.22. + /// + /// See [`bind()`](Self::bind()) for more details on `addrs` argument. + /// + /// ALPN protocols "h2" and "http/1.1" are added to any configured ones. + #[cfg(feature = "rustls-0_22")] + pub fn bind_rustls_0_22( + mut self, + addrs: A, + config: actix_tls::accept::rustls_0_22::reexports::ServerConfig, + ) -> io::Result { + let sockets = bind_addrs(addrs, self.backlog)?; + for lst in sockets { + self = self.listen_rustls_0_22_inner(lst, config.clone())?; + } + Ok(self) + } + /// Resolves socket address(es) and binds server to created listener(s) for TLS connections /// using OpenSSL. /// @@ -685,6 +704,72 @@ where Ok(self) } + /// Binds to existing listener for accepting incoming TLS connection requests using Rustls + /// v0.22. + /// + /// See [`listen()`](Self::listen) for more details on the `lst` argument. + /// + /// ALPN protocols "h2" and "http/1.1" are added to any configured ones. + #[cfg(feature = "rustls-0_22")] + pub fn listen_rustls_0_22( + self, + lst: net::TcpListener, + config: actix_tls::accept::rustls_0_22::reexports::ServerConfig, + ) -> io::Result { + self.listen_rustls_0_22_inner(lst, config) + } + + #[cfg(feature = "rustls-0_22")] + fn listen_rustls_0_22_inner( + mut self, + lst: net::TcpListener, + config: actix_tls::accept::rustls_0_22::reexports::ServerConfig, + ) -> io::Result { + let factory = self.factory.clone(); + let cfg = self.config.clone(); + let addr = lst.local_addr().unwrap(); + self.sockets.push(Socket { + addr, + scheme: "https", + }); + + let on_connect_fn = self.on_connect_fn.clone(); + + self.builder = + self.builder + .listen(format!("actix-web-service-{}", addr), lst, move || { + let c = cfg.lock().unwrap(); + let host = c.host.clone().unwrap_or_else(|| format!("{}", addr)); + + let svc = HttpService::build() + .keep_alive(c.keep_alive) + .client_request_timeout(c.client_request_timeout) + .client_disconnect_timeout(c.client_disconnect_timeout); + + let svc = if let Some(handler) = on_connect_fn.clone() { + svc.on_connect_ext(move |io: &_, ext: _| (handler)(io as &dyn Any, ext)) + } else { + svc + }; + + let fac = factory() + .into_factory() + .map_err(|err| err.into().error_response()); + + let acceptor_config = match c.tls_handshake_timeout { + Some(dur) => TlsAcceptorConfig::default().handshake_timeout(dur), + None => TlsAcceptorConfig::default(), + }; + + svc.finish(map_config(fac, move |_| { + AppConfig::new(true, host.clone(), addr) + })) + .rustls_0_22_with_config(config.clone(), acceptor_config) + })?; + + Ok(self) + } + /// Binds to existing listener for accepting incoming TLS connection requests using OpenSSL. /// /// See [`listen()`](Self::listen) for more details on the `lst` argument. diff --git a/actix-web/tests/test_server.rs b/actix-web/tests/test_server.rs index a268cb6e3..0df6e2124 100644 --- a/actix-web/tests/test_server.rs +++ b/actix-web/tests/test_server.rs @@ -743,7 +743,7 @@ mod plus_rustls { .map(char::from) .collect::(); - let srv = actix_test::start_with(actix_test::config().rustls_021(tls_config()), || { + let srv = actix_test::start_with(actix_test::config().rustls_0_21(tls_config()), || { App::new().service(web::resource("/").route(web::to(|bytes: Bytes| async { // echo decompressed request body back in response HttpResponse::Ok() diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 6f4212f90..3cef0e139 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -2,6 +2,9 @@ ## Unreleased +- Add `rustls-0_22-webpki-roots` and `rustls-0_22-native-roots` crate feature. +- Add `awc::Connector::rustls_0_22()` method. + ## 3.3.0 - Update `trust-dns-resolver` dependency to `0.23`. diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 5c09400a0..369119c25 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -20,8 +20,17 @@ name = "awc" path = "src/lib.rs" [package.metadata.docs.rs] -# features that docs.rs will build with -features = ["openssl", "rustls-0_20", "rustls-0_21", "compress-brotli", "compress-gzip", "compress-zstd", "cookies"] +rustdoc-args = ["--cfg", "docsrs"] +features = [ + "cookies", + "openssl", + "rustls-0_20", + "rustls-0_21", + "rustls-0_22-webpki-roots", + "compress-brotli", + "compress-gzip", + "compress-zstd", +] [features] default = ["compress-brotli", "compress-gzip", "compress-zstd", "cookies"] @@ -35,6 +44,10 @@ rustls = ["rustls-0_20"] rustls-0_20 = ["tls-rustls-0_20", "actix-tls/rustls-0_20"] # TLS via Rustls v0.21 rustls-0_21 = ["tls-rustls-0_21", "actix-tls/rustls-0_21"] +# TLS via Rustls v0.22 (WebPKI roots) +rustls-0_22-webpki-roots = ["tls-rustls-0_22", "actix-tls/rustls-0_22-webpki-roots"] +# TLS via Rustls v0.22 (Native roots) +rustls-0_22-native-roots = ["tls-rustls-0_22", "actix-tls/rustls-0_22-native-roots"] # Brotli algorithm content-encoding support compress-brotli = ["actix-http/compress-brotli", "__compress"] @@ -63,7 +76,7 @@ actix-codec = "0.5" actix-service = "2" actix-http = { version = "3.5", features = ["http2", "ws"] } actix-rt = { version = "2.1", default-features = false } -actix-tls = { version = "3.1", features = ["connect", "uri"] } +actix-tls = { version = "3.3", features = ["connect", "uri"] } actix-utils = "3" base64 = "0.21" @@ -90,6 +103,7 @@ cookie = { version = "0.16", features = ["percent-encode"], optional = true } tls-openssl = { package = "openssl", version = "0.10.55", optional = true } tls-rustls-0_20 = { package = "rustls", version = "0.20", optional = true, features = ["dangerous_configuration"] } tls-rustls-0_21 = { package = "rustls", version = "0.21", optional = true, features = ["dangerous_configuration"] } +tls-rustls-0_22 = { package = "rustls", version = "0.22", optional = true } trust-dns-resolver = { version = "0.23", optional = true } @@ -97,8 +111,8 @@ trust-dns-resolver = { version = "0.23", optional = true } actix-http = { version = "3.5", features = ["openssl"] } actix-http-test = { version = "3", features = ["openssl"] } actix-server = "2" -actix-test = { version = "0.1", features = ["openssl", "rustls-0_21"] } -actix-tls = { version = "3", features = ["openssl", "rustls-0_21"] } +actix-test = { version = "0.1", features = ["openssl", "rustls-0_22"] } +actix-tls = { version = "3.3", features = ["openssl", "rustls-0_22"] } actix-utils = "3" actix-web = { version = "4", features = ["openssl"] } @@ -108,11 +122,11 @@ env_logger = "0.10" flate2 = "1.0.13" futures-util = { version = "0.3.17", default-features = false } static_assertions = "1.1" -rcgen = "0.11" -rustls-pemfile = "1" +rcgen = "0.12" +rustls-pemfile = "2" tokio = { version = "1.24.2", features = ["rt-multi-thread", "macros"] } zstd = "0.13" [[example]] name = "client" -required-features = ["rustls-0_21"] +required-features = ["rustls-0_22-webpki-roots"] diff --git a/awc/src/client/connector.rs b/awc/src/client/connector.rs index 879d1895b..df6e422f3 100644 --- a/awc/src/client/connector.rs +++ b/awc/src/client/connector.rs @@ -40,14 +40,23 @@ enum OurTlsConnector { /// Provided because building the OpenSSL context on newer versions can be very slow. /// This prevents unnecessary calls to `.build()` while constructing the client connector. #[cfg(feature = "openssl")] - #[allow(dead_code)] // false positive; used in build_ssl + #[allow(dead_code)] // false positive; used in build_tls OpensslBuilder(actix_tls::connect::openssl::reexports::SslConnectorBuilder), #[cfg(feature = "rustls-0_20")] + #[allow(dead_code)] // false positive; used in build_tls Rustls020(std::sync::Arc), #[cfg(feature = "rustls-0_21")] + #[allow(dead_code)] // false positive; used in build_tls Rustls021(std::sync::Arc), + + #[cfg(any( + feature = "rustls-0_22-webpki-roots", + feature = "rustls-0_22-native-roots", + ))] + #[allow(dead_code)] // false positive; used in build_tls + Rustls022(std::sync::Arc), } /// Manages HTTP client network connectivity. @@ -86,67 +95,83 @@ impl Connector<()> { } } - /// Provides an empty TLS connector when no TLS feature is enabled. - #[cfg(not(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21")))] - fn build_tls(_: Vec>) -> OurTlsConnector { - OurTlsConnector::None - } + cfg_if::cfg_if! { + if #[cfg(any(feature = "rustls-0_22-webpki-roots", feature = "rustls-0_22-webpki-roots"))] { + /// Build TLS connector with Rustls v0.22, based on supplied ALPN protocols. + /// + /// Note that if other TLS crate features are enabled, Rustls v0.22 will be used. + fn build_tls(protocols: Vec>) -> OurTlsConnector { + use actix_tls::connect::rustls_0_22::{self, reexports::ClientConfig}; - /// Build TLS connector with Rustls v0.21, based on supplied ALPN protocols - /// - /// Note that if other TLS crate features are enabled, Rustls v0.21 will be used. - #[cfg(feature = "rustls-0_21")] - fn build_tls(protocols: Vec>) -> OurTlsConnector { - use actix_tls::connect::rustls_0_21::{reexports::ClientConfig, webpki_roots_cert_store}; + cfg_if::cfg_if! { + if #[cfg(feature = "rustls-0_22-webpki-roots")] { + let certs = rustls_0_22::webpki_roots_cert_store(); + } else if #[cfg(feature = "rustls-0_22-native-roots")] { + let certs = rustls_0_22::native_roots_cert_store(); + } + } - let mut config = ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(webpki_roots_cert_store()) - .with_no_client_auth(); + let mut config = ClientConfig::builder() + .with_root_certificates(certs) + .with_no_client_auth(); - config.alpn_protocols = protocols; + config.alpn_protocols = protocols; - OurTlsConnector::Rustls021(std::sync::Arc::new(config)) - } + OurTlsConnector::Rustls022(std::sync::Arc::new(config)) + } + } else if #[cfg(feature = "rustls-0_21")] { + /// Build TLS connector with Rustls v0.21, based on supplied ALPN protocols. + fn build_tls(protocols: Vec>) -> OurTlsConnector { + use actix_tls::connect::rustls_0_21::{reexports::ClientConfig, webpki_roots_cert_store}; - /// Build TLS connector with Rustls v0.20, based on supplied ALPN protocols - /// - /// Note that if other TLS crate features are enabled, Rustls v0.21 will be used. - #[cfg(all(feature = "rustls-0_20", not(feature = "rustls-0_21")))] - fn build_tls(protocols: Vec>) -> OurTlsConnector { - use actix_tls::connect::rustls_0_20::{reexports::ClientConfig, webpki_roots_cert_store}; + let mut config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(webpki_roots_cert_store()) + .with_no_client_auth(); - let mut config = ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(webpki_roots_cert_store()) - .with_no_client_auth(); + config.alpn_protocols = protocols; - config.alpn_protocols = protocols; + OurTlsConnector::Rustls021(std::sync::Arc::new(config)) + } + } else if #[cfg(feature = "rustls-0_20")] { + /// Build TLS connector with Rustls v0.20, based on supplied ALPN protocols. + fn build_tls(protocols: Vec>) -> OurTlsConnector { + use actix_tls::connect::rustls_0_20::{reexports::ClientConfig, webpki_roots_cert_store}; - OurTlsConnector::Rustls020(std::sync::Arc::new(config)) - } + let mut config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(webpki_roots_cert_store()) + .with_no_client_auth(); - /// Build TLS connector with OpenSSL, based on supplied ALPN protocols - #[cfg(all( - feature = "openssl", - not(any(feature = "rustls-0_20", feature = "rustls-0_21")), - ))] - fn build_tls(protocols: Vec>) -> OurTlsConnector { - use actix_tls::connect::openssl::reexports::{SslConnector, SslMethod}; - use bytes::{BufMut, BytesMut}; + config.alpn_protocols = protocols; - let mut alpn = BytesMut::with_capacity(20); - for proto in &protocols { - alpn.put_u8(proto.len() as u8); - alpn.put(proto.as_slice()); + OurTlsConnector::Rustls020(std::sync::Arc::new(config)) + } + } else if #[cfg(feature = "openssl")] { + /// Build TLS connector with OpenSSL, based on supplied ALPN protocols. + fn build_tls(protocols: Vec>) -> OurTlsConnector { + use actix_tls::connect::openssl::reexports::{SslConnector, SslMethod}; + use bytes::{BufMut, BytesMut}; + + let mut alpn = BytesMut::with_capacity(20); + for proto in &protocols { + alpn.put_u8(proto.len() as u8); + alpn.put(proto.as_slice()); + } + + let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); + if let Err(err) = ssl.set_alpn_protos(&alpn) { + log::error!("Can not set ALPN protocol: {err:?}"); + } + + OurTlsConnector::OpensslBuilder(ssl) + } + } else { + /// Provides an empty TLS connector when no TLS feature is enabled. + fn build_tls(_: Vec>) -> OurTlsConnector { + OurTlsConnector::None + } } - - let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - if let Err(err) = ssl.set_alpn_protos(&alpn) { - log::error!("Can not set ALPN protocol: {:?}", err); - } - - OurTlsConnector::OpensslBuilder(ssl) } } @@ -240,6 +265,19 @@ where self } + /// Sets custom Rustls v0.22 `ClientConfig` instance. + #[cfg(any( + feature = "rustls-0_22-webpki-roots", + feature = "rustls-0_22-native-roots", + ))] + pub fn rustls_0_22( + mut self, + connector: std::sync::Arc, + ) -> Self { + self.tls = OurTlsConnector::Rustls022(connector); + self + } + /// Sets maximum supported HTTP major version. /// /// Supported versions are HTTP/1.1 and HTTP/2. @@ -509,6 +547,42 @@ where Some(actix_service::boxed::rc_service(tls_service)) } + + #[cfg(any( + feature = "rustls-0_22-webpki-roots", + feature = "rustls-0_22-native-roots", + ))] + OurTlsConnector::Rustls022(tls) => { + const H2: &[u8] = b"h2"; + + use actix_tls::connect::rustls_0_22::{reexports::AsyncTlsStream, TlsConnector}; + + impl IntoConnectionIo for TcpConnection> { + fn into_connection_io(self) -> (Box, Protocol) { + let sock = self.into_parts().0; + let h2 = sock + .get_ref() + .1 + .alpn_protocol() + .map_or(false, |protos| protos.windows(2).any(|w| w == H2)); + if h2 { + (Box::new(sock), Protocol::Http2) + } else { + (Box::new(sock), Protocol::Http1) + } + } + } + + let handshake_timeout = self.config.handshake_timeout; + + let tls_service = TlsConnectorService { + tcp_service: tcp_service_inner, + tls_service: TlsConnector::service(tls), + timeout: handshake_timeout, + }; + + Some(actix_service::boxed::rc_service(tls_service)) + } }; let tcp_config = self.config.no_disconnect_timeout(); diff --git a/awc/tests/test_rustls_client.rs b/awc/tests/test_rustls_client.rs index d758f93d8..1cc3e8c48 100644 --- a/awc/tests/test_rustls_client.rs +++ b/awc/tests/test_rustls_client.rs @@ -1,6 +1,6 @@ -#![cfg(feature = "rustls-0_21")] +#![cfg(feature = "rustls-0_22-webpki-roots")] -extern crate tls_rustls_0_21 as rustls; +extern crate tls_rustls_0_22 as rustls; use std::{ io::BufReader, @@ -8,18 +8,17 @@ use std::{ atomic::{AtomicUsize, Ordering}, Arc, }, - time::SystemTime, }; use actix_http::HttpService; use actix_http_test::test_server; use actix_service::{fn_service, map_config, ServiceFactoryExt}; -use actix_tls::connect::rustls_0_21::webpki_roots_cert_store; +use actix_tls::connect::rustls_0_22::webpki_roots_cert_store; use actix_utils::future::ok; use actix_web::{dev::AppConfig, http::Version, web, App, HttpResponse}; use rustls::{ - client::{ServerCertVerified, ServerCertVerifier}, - Certificate, ClientConfig, PrivateKey, ServerConfig, ServerName, + pki_types::{CertificateDer, PrivateKeyDer, ServerName}, + ClientConfig, ServerConfig, }; use rustls_pemfile::{certs, pkcs8_private_keys}; @@ -31,36 +30,62 @@ fn tls_config() -> ServerConfig { let cert_file = &mut BufReader::new(cert_file.as_bytes()); let key_file = &mut BufReader::new(key_file.as_bytes()); - let cert_chain = certs(cert_file) - .unwrap() - .into_iter() - .map(Certificate) - .collect(); - let mut keys = pkcs8_private_keys(key_file).unwrap(); + let cert_chain = certs(cert_file).collect::, _>>().unwrap(); + let mut keys = pkcs8_private_keys(key_file) + .collect::, _>>() + .unwrap(); ServerConfig::builder() - .with_safe_defaults() .with_no_client_auth() - .with_single_cert(cert_chain, PrivateKey(keys.remove(0))) + .with_single_cert(cert_chain, PrivateKeyDer::Pkcs8(keys.remove(0))) .unwrap() } mod danger { + use rustls::{ + client::danger::{ServerCertVerified, ServerCertVerifier}, + pki_types::UnixTime, + }; + use super::*; + #[derive(Debug)] pub struct NoCertificateVerification; impl ServerCertVerifier for NoCertificateVerification { fn verify_server_cert( &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _server_name: &ServerName, - _scts: &mut dyn Iterator, + _end_entity: &CertificateDer<'_>, + _intermediates: &[CertificateDer<'_>], + _server_name: &ServerName<'_>, _ocsp_response: &[u8], - _now: SystemTime, + _now: UnixTime, ) -> Result { - Ok(ServerCertVerified::assertion()) + Ok(rustls::client::danger::ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + _message: &[u8], + _cert: &CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + _message: &[u8], + _cert: &CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + rustls::crypto::ring::default_provider() + .signature_verification_algorithms + .supported_schemes() } } } @@ -82,14 +107,13 @@ async fn test_connection_reuse_h2() { App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))), |_| AppConfig::default(), )) - .rustls_021(tls_config()) + .rustls_0_22(tls_config()) .map_err(|_| ()), ) }) .await; let mut config = ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(webpki_roots_cert_store()) .with_no_client_auth(); @@ -102,7 +126,7 @@ async fn test_connection_reuse_h2() { .set_certificate_verifier(Arc::new(danger::NoCertificateVerification)); let client = awc::Client::builder() - .connector(awc::Connector::new().rustls_021(Arc::new(config))) + .connector(awc::Connector::new().rustls_0_22(Arc::new(config))) .finish(); // req 1 From 8db3de6edee25090edb377d4ae858747191e38c6 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 00:31:14 +0000 Subject: [PATCH 03/14] chore(actix-http): prepare release 3.6.0 --- actix-http/CHANGES.md | 2 ++ actix-http/Cargo.toml | 2 +- actix-http/README.md | 4 ++-- actix-test/Cargo.toml | 2 +- actix-web/Cargo.toml | 2 +- awc/Cargo.toml | 4 ++-- scripts/bump | 1 - 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index aca2a2573..e3805ff7e 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.6.0 + ### Added - Add `rustls-0_22` crate feature. diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 3a3000169..14b9bdacb 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http" -version = "3.5.1" +version = "3.6.0" authors = [ "Nikolay Kim ", "Rob Ede ", diff --git a/actix-http/README.md b/actix-http/README.md index 9d80c10c4..c9bd1b34c 100644 --- a/actix-http/README.md +++ b/actix-http/README.md @@ -5,11 +5,11 @@ [![crates.io](https://img.shields.io/crates/v/actix-http?label=latest)](https://crates.io/crates/actix-http) -[![Documentation](https://docs.rs/actix-http/badge.svg?version=3.5.1)](https://docs.rs/actix-http/3.5.1) +[![Documentation](https://docs.rs/actix-http/badge.svg?version=3.6.0)](https://docs.rs/actix-http/3.6.0) ![Version](https://img.shields.io/badge/rustc-1.68+-ab6000.svg) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-http.svg)
-[![dependency status](https://deps.rs/crate/actix-http/3.5.1/status.svg)](https://deps.rs/crate/actix-http/3.5.1) +[![dependency status](https://deps.rs/crate/actix-http/3.6.0/status.svg)](https://deps.rs/crate/actix-http/3.6.0) [![Download](https://img.shields.io/crates/d/actix-http.svg)](https://crates.io/crates/actix-http) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) diff --git a/actix-test/Cargo.toml b/actix-test/Cargo.toml index d5be25384..c24e1363d 100644 --- a/actix-test/Cargo.toml +++ b/actix-test/Cargo.toml @@ -35,7 +35,7 @@ openssl = ["tls-openssl", "actix-http/openssl", "awc/openssl"] [dependencies] actix-codec = "0.5" -actix-http = "3" +actix-http = "3.6" actix-http-test = "3" actix-rt = "2.1" actix-service = "2" diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index 37299721f..167927263 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -88,7 +88,7 @@ actix-service = "2" actix-utils = "3" actix-tls = { version = "3.3", default-features = false, optional = true } -actix-http = { version = "3.5", features = ["ws"] } +actix-http = { version = "3.6", features = ["ws"] } actix-router = "0.5" actix-web-codegen = { version = "4.2", optional = true } diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 369119c25..46603fed2 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -74,7 +74,7 @@ dangerous-h2c = [] [dependencies] actix-codec = "0.5" actix-service = "2" -actix-http = { version = "3.5", features = ["http2", "ws"] } +actix-http = { version = "3.6", features = ["http2", "ws"] } actix-rt = { version = "2.1", default-features = false } actix-tls = { version = "3.3", features = ["connect", "uri"] } actix-utils = "3" @@ -108,7 +108,7 @@ tls-rustls-0_22 = { package = "rustls", version = "0.22", optional = true } trust-dns-resolver = { version = "0.23", optional = true } [dev-dependencies] -actix-http = { version = "3.5", features = ["openssl"] } +actix-http = { version = "3.6", features = ["openssl"] } actix-http-test = { version = "3", features = ["openssl"] } actix-server = "2" actix-test = { version = "0.1", features = ["openssl", "rustls-0_22"] } diff --git a/scripts/bump b/scripts/bump index 22aa2af95..6fd879eae 100755 --- a/scripts/bump +++ b/scripts/bump @@ -112,7 +112,6 @@ echo read -p "Update all references: (y/N) " UPDATE_REFERENCES UPDATE_REFERENCES="${UPDATE_REFERENCES:-n}" - if [ "$UPDATE_REFERENCES" = 'y' ] || [ "$UPDATE_REFERENCES" = 'Y' ]; then if [[ $NEW_VERSION == *".0.0" ]]; then NEW_VERSION_SPEC="${NEW_VERSION%.0.0}" From 8e9e9fbcdd727d54361ea165ce64af74375c9f81 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 00:32:28 +0000 Subject: [PATCH 04/14] chore(actix-web): prepare release 4.5.0 --- actix-test/Cargo.toml | 2 +- actix-web/CHANGES.md | 2 ++ actix-web/Cargo.toml | 2 +- actix-web/README.md | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/actix-test/Cargo.toml b/actix-test/Cargo.toml index c24e1363d..4e6ea0869 100644 --- a/actix-test/Cargo.toml +++ b/actix-test/Cargo.toml @@ -40,7 +40,7 @@ actix-http-test = "3" actix-rt = "2.1" actix-service = "2" actix-utils = "3" -actix-web = { version = "4", default-features = false, features = ["cookies"] } +actix-web = { version = "4.5", default-features = false, features = ["cookies"] } awc = { version = "3", default-features = false, features = ["cookies"] } futures-core = { version = "0.3.17", default-features = false, features = ["std"] } diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md index 072cdc012..174a70e6f 100644 --- a/actix-web/CHANGES.md +++ b/actix-web/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.5.0 + - Add `rustls-0_22` crate feature. - Add `HttpServer::{bind_rustls_0_22, listen_rustls_0_22}()` builder methods. diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index 167927263..985a103f2 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web" -version = "4.4.1" +version = "4.5.0" description = "Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust" authors = [ "Nikolay Kim ", diff --git a/actix-web/README.md b/actix-web/README.md index 80ae21238..492f06fa3 100644 --- a/actix-web/README.md +++ b/actix-web/README.md @@ -8,10 +8,10 @@ [![crates.io](https://img.shields.io/crates/v/actix-web?label=latest)](https://crates.io/crates/actix-web) -[![Documentation](https://docs.rs/actix-web/badge.svg?version=4.4.1)](https://docs.rs/actix-web/4.4.1) +[![Documentation](https://docs.rs/actix-web/badge.svg?version=4.5.0)](https://docs.rs/actix-web/4.5.0) ![MSRV](https://img.shields.io/badge/rustc-1.68+-ab6000.svg) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-web.svg) -[![Dependency Status](https://deps.rs/crate/actix-web/4.4.1/status.svg)](https://deps.rs/crate/actix-web/4.4.1) +[![Dependency Status](https://deps.rs/crate/actix-web/4.5.0/status.svg)](https://deps.rs/crate/actix-web/4.5.0)
[![CI](https://github.com/actix/actix-web/actions/workflows/ci.yml/badge.svg)](https://github.com/actix/actix-web/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) From 73fa1184f18bd36668dfb2fbf30ced578b928833 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 00:32:57 +0000 Subject: [PATCH 05/14] chore(awc): prepare release 3.4.0 --- actix-test/Cargo.toml | 2 +- awc/CHANGES.md | 2 ++ awc/Cargo.toml | 2 +- awc/README.md | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/actix-test/Cargo.toml b/actix-test/Cargo.toml index 4e6ea0869..49ba22d51 100644 --- a/actix-test/Cargo.toml +++ b/actix-test/Cargo.toml @@ -41,7 +41,7 @@ actix-rt = "2.1" actix-service = "2" actix-utils = "3" actix-web = { version = "4.5", default-features = false, features = ["cookies"] } -awc = { version = "3", default-features = false, features = ["cookies"] } +awc = { version = "3.4", default-features = false, features = ["cookies"] } futures-core = { version = "0.3.17", default-features = false, features = ["std"] } futures-util = { version = "0.3.17", default-features = false, features = [] } diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 3cef0e139..4ed02ada6 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.4.0 + - Add `rustls-0_22-webpki-roots` and `rustls-0_22-native-roots` crate feature. - Add `awc::Connector::rustls_0_22()` method. diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 46603fed2..14d93ac30 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "awc" -version = "3.3.0" +version = "3.4.0" authors = ["Nikolay Kim "] description = "Async HTTP and WebSocket client library" keywords = ["actix", "http", "framework", "async", "web"] diff --git a/awc/README.md b/awc/README.md index 424c86bba..d86657564 100644 --- a/awc/README.md +++ b/awc/README.md @@ -5,9 +5,9 @@ [![crates.io](https://img.shields.io/crates/v/awc?label=latest)](https://crates.io/crates/awc) -[![Documentation](https://docs.rs/awc/badge.svg?version=3.3.0)](https://docs.rs/awc/3.3.0) +[![Documentation](https://docs.rs/awc/badge.svg?version=3.4.0)](https://docs.rs/awc/3.4.0) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/awc) -[![Dependency Status](https://deps.rs/crate/awc/3.3.0/status.svg)](https://deps.rs/crate/awc/3.3.0) +[![Dependency Status](https://deps.rs/crate/awc/3.4.0/status.svg)](https://deps.rs/crate/awc/3.4.0) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) From 17ed73b33e0fb7d3257da4c98039496044154c35 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 00:33:38 +0000 Subject: [PATCH 06/14] chore(actix-web-actors): prepare release 4.3.0 --- actix-web-actors/CHANGES.md | 2 ++ actix-web-actors/Cargo.toml | 2 +- actix-web-actors/README.md | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/actix-web-actors/CHANGES.md b/actix-web-actors/CHANGES.md index 5c516db56..85d6b624a 100644 --- a/actix-web-actors/CHANGES.md +++ b/actix-web-actors/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.3.0 + - Minimum supported Rust version (MSRV) is now 1.68 due to transitive `time` dependency. ## 4.2.0 diff --git a/actix-web-actors/Cargo.toml b/actix-web-actors/Cargo.toml index c6f14554a..0263e9b29 100644 --- a/actix-web-actors/Cargo.toml +++ b/actix-web-actors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web-actors" -version = "4.2.0" +version = "4.3.0" authors = ["Nikolay Kim "] description = "Actix actors support for Actix Web" keywords = ["actix", "http", "web", "framework", "async"] diff --git a/actix-web-actors/README.md b/actix-web-actors/README.md index c81fe64c1..17b947223 100644 --- a/actix-web-actors/README.md +++ b/actix-web-actors/README.md @@ -5,11 +5,11 @@ [![crates.io](https://img.shields.io/crates/v/actix-web-actors?label=latest)](https://crates.io/crates/actix-web-actors) -[![Documentation](https://docs.rs/actix-web-actors/badge.svg?version=4.2.0)](https://docs.rs/actix-web-actors/4.2.0) +[![Documentation](https://docs.rs/actix-web-actors/badge.svg?version=4.3.0)](https://docs.rs/actix-web-actors/4.3.0) ![Version](https://img.shields.io/badge/rustc-1.68+-ab6000.svg) ![License](https://img.shields.io/crates/l/actix-web-actors.svg)
-[![dependency status](https://deps.rs/crate/actix-web-actors/4.2.0/status.svg)](https://deps.rs/crate/actix-web-actors/4.2.0) +[![dependency status](https://deps.rs/crate/actix-web-actors/4.3.0/status.svg)](https://deps.rs/crate/actix-web-actors/4.3.0) [![Download](https://img.shields.io/crates/d/actix-web-actors.svg)](https://crates.io/crates/actix-web-actors) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) From 3f2fd2d59f64c172a944ddf82787e7d31e6a1b95 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 00:33:42 +0000 Subject: [PATCH 07/14] chore(actix-test): prepare release 0.1.3 --- actix-test/CHANGES.md | 2 ++ actix-test/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/actix-test/CHANGES.md b/actix-test/CHANGES.md index bdacc8b2d..8604a1265 100644 --- a/actix-test/CHANGES.md +++ b/actix-test/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.1.3 + - Add `TestServerConfig::rustls_0_22()` method for Rustls v0.22 support behind new `rustls-0_22` crate feature. ## 0.1.2 diff --git a/actix-test/Cargo.toml b/actix-test/Cargo.toml index 49ba22d51..7f48fc2cc 100644 --- a/actix-test/Cargo.toml +++ b/actix-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-test" -version = "0.1.2" +version = "0.1.3" authors = [ "Nikolay Kim ", "Rob Ede ", From 59bc85fe0e5961b9e3499a3272737b780904955d Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 00:34:00 +0000 Subject: [PATCH 08/14] chore(actix-http-test): prepare release 3.2.0 --- actix-http-test/CHANGES.md | 2 ++ actix-http-test/Cargo.toml | 2 +- actix-http-test/README.md | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/actix-http-test/CHANGES.md b/actix-http-test/CHANGES.md index 065141b20..ec30b9c4c 100644 --- a/actix-http-test/CHANGES.md +++ b/actix-http-test/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.2.0 + - Minimum supported Rust version (MSRV) is now 1.68 due to transitive `time` dependency. ## 3.1.0 diff --git a/actix-http-test/Cargo.toml b/actix-http-test/Cargo.toml index 0881e0bc4..bfb0a3539 100644 --- a/actix-http-test/Cargo.toml +++ b/actix-http-test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-http-test" -version = "3.1.0" +version = "3.2.0" authors = ["Nikolay Kim "] description = "Various helpers for Actix applications to use during testing" keywords = ["http", "web", "framework", "async", "futures"] diff --git a/actix-http-test/README.md b/actix-http-test/README.md index e544c3616..9a87f9ef2 100644 --- a/actix-http-test/README.md +++ b/actix-http-test/README.md @@ -5,11 +5,11 @@ [![crates.io](https://img.shields.io/crates/v/actix-http-test?label=latest)](https://crates.io/crates/actix-http-test) -[![Documentation](https://docs.rs/actix-http-test/badge.svg?version=3.1.0)](https://docs.rs/actix-http-test/3.1.0) +[![Documentation](https://docs.rs/actix-http-test/badge.svg?version=3.2.0)](https://docs.rs/actix-http-test/3.2.0) ![Version](https://img.shields.io/badge/rustc-1.68+-ab6000.svg) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-http-test)
-[![Dependency Status](https://deps.rs/crate/actix-http-test/3.1.0/status.svg)](https://deps.rs/crate/actix-http-test/3.1.0) +[![Dependency Status](https://deps.rs/crate/actix-http-test/3.2.0/status.svg)](https://deps.rs/crate/actix-http-test/3.2.0) [![Download](https://img.shields.io/crates/d/actix-http-test.svg)](https://crates.io/crates/actix-http-test) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) From 2b8c528e543a7d663d2e0bcc89dfaffa0d8a77f7 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 01:22:36 +0000 Subject: [PATCH 09/14] chore(actix-web): prepare release 4.5.1 --- actix-web/CHANGES.md | 8 ++++++++ actix-web/Cargo.toml | 2 +- actix-web/README.md | 4 ++-- actix-web/src/server.rs | 7 ++++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md index 174a70e6f..6e2894e40 100644 --- a/actix-web/CHANGES.md +++ b/actix-web/CHANGES.md @@ -2,8 +2,16 @@ ## Unreleased +## 4.5.1 + +### Fixed + +- Fix missing import when using enabling Rustls v0.22 support. + ## 4.5.0 +### Added + - Add `rustls-0_22` crate feature. - Add `HttpServer::{bind_rustls_0_22, listen_rustls_0_22}()` builder methods. diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index 985a103f2..8c1cc9bfe 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-web" -version = "4.5.0" +version = "4.5.1" description = "Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust" authors = [ "Nikolay Kim ", diff --git a/actix-web/README.md b/actix-web/README.md index 492f06fa3..b564c8793 100644 --- a/actix-web/README.md +++ b/actix-web/README.md @@ -8,10 +8,10 @@ [![crates.io](https://img.shields.io/crates/v/actix-web?label=latest)](https://crates.io/crates/actix-web) -[![Documentation](https://docs.rs/actix-web/badge.svg?version=4.5.0)](https://docs.rs/actix-web/4.5.0) +[![Documentation](https://docs.rs/actix-web/badge.svg?version=4.5.1)](https://docs.rs/actix-web/4.5.1) ![MSRV](https://img.shields.io/badge/rustc-1.68+-ab6000.svg) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-web.svg) -[![Dependency Status](https://deps.rs/crate/actix-web/4.5.0/status.svg)](https://deps.rs/crate/actix-web/4.5.0) +[![Dependency Status](https://deps.rs/crate/actix-web/4.5.1/status.svg)](https://deps.rs/crate/actix-web/4.5.1)
[![CI](https://github.com/actix/actix-web/actions/workflows/ci.yml/badge.svg)](https://github.com/actix/actix-web/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) diff --git a/actix-web/src/server.rs b/actix-web/src/server.rs index 193a7cce9..6592079bf 100644 --- a/actix-web/src/server.rs +++ b/actix-web/src/server.rs @@ -7,7 +7,12 @@ use std::{ time::Duration, }; -#[cfg(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21"))] +#[cfg(any( + feature = "openssl", + feature = "rustls-0_20", + feature = "rustls-0_21", + feature = "rustls-0_22", +))] use actix_http::TlsAcceptorConfig; use actix_http::{body::MessageBody, Extensions, HttpService, KeepAlive, Request, Response}; use actix_server::{Server, ServerBuilder}; From d9b31b80ac4c3e58444248b5e5b531fae557af14 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 03:11:48 +0000 Subject: [PATCH 10/14] fix: standardize body stream error reporting --- actix-http/examples/h2c-detect.rs | 9 +++++++-- actix-http/src/h1/dispatcher.rs | 5 ++++- actix-http/src/h2/dispatcher.rs | 15 ++++++++------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/actix-http/examples/h2c-detect.rs b/actix-http/examples/h2c-detect.rs index aa3dd5d31..b0bde3fe6 100644 --- a/actix-http/examples/h2c-detect.rs +++ b/actix-http/examples/h2c-detect.rs @@ -8,7 +8,7 @@ use std::{convert::Infallible, io}; -use actix_http::{HttpService, Request, Response, StatusCode}; +use actix_http::{body::BodyStream, HttpService, Request, Response, StatusCode}; use actix_server::Server; #[tokio::main(flavor = "current_thread")] @@ -19,7 +19,12 @@ async fn main() -> io::Result<()> { .bind("h2c-detect", ("127.0.0.1", 8080), || { HttpService::build() .finish(|_req: Request| async move { - Ok::<_, Infallible>(Response::build(StatusCode::OK).body("Hello!")) + Ok::<_, Infallible>(Response::build(StatusCode::OK).body(BodyStream::new( + futures_util::stream::iter([ + Ok::<_, String>("123".into()), + Err("wertyuikmnbvcxdfty6t".to_owned()), + ]), + ))) }) .tcp_auto_h2c() })? diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs index 270707807..bfbcaf24c 100644 --- a/actix-http/src/h1/dispatcher.rs +++ b/actix-http/src/h1/dispatcher.rs @@ -512,8 +512,10 @@ where } Poll::Ready(Some(Err(err))) => { + let err = err.into(); + tracing::error!("Response payload stream error: {err:?}"); this.flags.insert(Flags::FINISHED); - return Err(DispatchError::Body(err.into())); + return Err(DispatchError::Body(err)); } Poll::Pending => return Ok(PollResponse::DoNothing), @@ -549,6 +551,7 @@ where } Poll::Ready(Some(Err(err))) => { + tracing::error!("Response payload stream error: {err:?}"); this.flags.insert(Flags::FINISHED); return Err(DispatchError::Body( Error::new_body().with_cause(err).into(), diff --git a/actix-http/src/h2/dispatcher.rs b/actix-http/src/h2/dispatcher.rs index 3e618820e..022239c2d 100644 --- a/actix-http/src/h2/dispatcher.rs +++ b/actix-http/src/h2/dispatcher.rs @@ -4,7 +4,7 @@ use std::{ future::Future, marker::PhantomData, net, - pin::Pin, + pin::{pin, Pin}, rc::Rc, task::{Context, Poll}, }; @@ -20,7 +20,6 @@ use h2::{ Ping, PingPong, }; use pin_project_lite::pin_project; -use tracing::{error, trace, warn}; use crate::{ body::{BodySize, BoxBody, MessageBody}, @@ -147,11 +146,13 @@ where if let Err(err) = res { match err { DispatchError::SendResponse(err) => { - trace!("Error sending HTTP/2 response: {:?}", err) + tracing::trace!("Error sending response: {err:?}"); + } + DispatchError::SendData(err) => { + tracing::warn!("Send data error: {err:?}"); } - DispatchError::SendData(err) => warn!("{:?}", err), DispatchError::ResponseBody(err) => { - error!("Response payload stream error: {:?}", err) + tracing::error!("Response payload stream error: {err:?}"); } } } @@ -228,9 +229,9 @@ where return Ok(()); } - // poll response body and send chunks to client - actix_rt::pin!(body); + let mut body = pin!(body); + // poll response body and send chunks to client while let Some(res) = poll_fn(|cx| body.as_mut().poll_next(cx)).await { let mut chunk = res.map_err(|err| DispatchError::ResponseBody(err.into()))?; From f5f6132f948ec8d30251cfc13523db1827f25e2e Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 03:30:16 +0000 Subject: [PATCH 11/14] test: update rustls for test_server --- actix-web/Cargo.toml | 6 +++--- actix-web/tests/test_server.rs | 19 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index 8c1cc9bfe..aedcb3ef4 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -128,12 +128,12 @@ env_logger = "0.10" flate2 = "1.0.13" futures-util = { version = "0.3.17", default-features = false, features = ["std"] } rand = "0.8" -rcgen = "0.11" -rustls-pemfile = "1" +rcgen = "0.12" +rustls-pemfile = "2" serde = { version = "1.0", features = ["derive"] } static_assertions = "1" tls-openssl = { package = "openssl", version = "0.10.55" } -tls-rustls = { package = "rustls", version = "0.21" } +tls-rustls = { package = "rustls", version = "0.22" } tokio = { version = "1.24.2", features = ["rt-multi-thread", "macros"] } zstd = "0.13" diff --git a/actix-web/tests/test_server.rs b/actix-web/tests/test_server.rs index 0df6e2124..36f45c146 100644 --- a/actix-web/tests/test_server.rs +++ b/actix-web/tests/test_server.rs @@ -1,6 +1,6 @@ #[cfg(feature = "openssl")] extern crate tls_openssl as openssl; -#[cfg(feature = "rustls-0_21")] +#[cfg(feature = "rustls-0_22")] extern crate tls_rustls as rustls; use std::{ @@ -708,7 +708,7 @@ async fn test_brotli_encoding_large_openssl() { mod plus_rustls { use std::io::BufReader; - use rustls::{Certificate, PrivateKey, ServerConfig as RustlsServerConfig}; + use rustls::{pki_types::PrivateKeyDer, ServerConfig as RustlsServerConfig}; use rustls_pemfile::{certs, pkcs8_private_keys}; use super::*; @@ -721,17 +721,14 @@ mod plus_rustls { let cert_file = &mut BufReader::new(cert_file.as_bytes()); let key_file = &mut BufReader::new(key_file.as_bytes()); - let cert_chain = certs(cert_file) - .unwrap() - .into_iter() - .map(Certificate) - .collect(); - let mut keys = pkcs8_private_keys(key_file).unwrap(); + let cert_chain = certs(cert_file).collect::, _>>().unwrap(); + let mut keys = pkcs8_private_keys(key_file) + .collect::, _>>() + .unwrap(); RustlsServerConfig::builder() - .with_safe_defaults() .with_no_client_auth() - .with_single_cert(cert_chain, PrivateKey(keys.remove(0))) + .with_single_cert(cert_chain, PrivateKeyDer::Pkcs8(keys.remove(0))) .unwrap() } @@ -743,7 +740,7 @@ mod plus_rustls { .map(char::from) .collect::(); - let srv = actix_test::start_with(actix_test::config().rustls_0_21(tls_config()), || { + let srv = actix_test::start_with(actix_test::config().rustls_0_22(tls_config()), || { App::new().service(web::resource("/").route(web::to(|bytes: Bytes| async { // echo decompressed request body back in response HttpResponse::Ok() From e518170a30e6bd32c6a42b1ff20f46126ca1f8a8 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 4 Feb 2024 03:40:58 +0000 Subject: [PATCH 12/14] test: fix test_server --- actix-web/Cargo.toml | 2 +- actix-web/tests/test_server.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml index aedcb3ef4..b045589bd 100644 --- a/actix-web/Cargo.toml +++ b/actix-web/Cargo.toml @@ -118,7 +118,7 @@ url = "2.1" [dev-dependencies] actix-files = "0.6" -actix-test = { version = "0.1", features = ["openssl", "rustls-0_21"] } +actix-test = { version = "0.1", features = ["openssl", "rustls-0_22"] } awc = { version = "3", features = ["openssl"] } brotli = "3.3.3" diff --git a/actix-web/tests/test_server.rs b/actix-web/tests/test_server.rs index 36f45c146..8fb80216b 100644 --- a/actix-web/tests/test_server.rs +++ b/actix-web/tests/test_server.rs @@ -704,7 +704,7 @@ async fn test_brotli_encoding_large_openssl() { srv.stop().await; } -#[cfg(feature = "rustls-0_21")] +#[cfg(feature = "rustls-0_22")] mod plus_rustls { use std::io::BufReader; From 373d4ca970bce4ab68d2c55a82d8e493cc550890 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 01:27:57 +0000 Subject: [PATCH 13/14] build(deps): bump codecov/codecov-action from 4.0.0 to 4.0.1 (#3279) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index d871898f3..9fef98dcd 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -31,7 +31,7 @@ jobs: run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4.0.0 + uses: codecov/codecov-action@v4.0.1 with: files: codecov.json fail_ci_if_error: true From 7e4e12b0aa674c96e8abe9c79b8bd1fe4fcb5cb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 14:38:02 +0000 Subject: [PATCH 14/14] build(deps): bump taiki-e/install-action from 2.26.8 to 2.26.12 (#3280) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci-post-merge.yml | 6 +++--- .github/workflows/ci.yml | 2 +- .github/workflows/coverage.yml | 2 +- .github/workflows/lint.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-post-merge.yml b/.github/workflows/ci-post-merge.yml index de9b30a59..1a0437cbe 100644 --- a/.github/workflows/ci-post-merge.yml +++ b/.github/workflows/ci-post-merge.yml @@ -45,7 +45,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack and cargo-ci-cache-clean - uses: taiki-e/install-action@v2.26.8 + uses: taiki-e/install-action@v2.26.12 with: tool: cargo-hack,cargo-ci-cache-clean @@ -85,7 +85,7 @@ jobs: uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - name: Install cargo-hack - uses: taiki-e/install-action@v2.26.8 + uses: taiki-e/install-action@v2.26.12 with: tool: cargo-hack @@ -106,7 +106,7 @@ jobs: uses: actions-rust-lang/setup-rust-toolchain@v1.8.0 - name: Install nextest - uses: taiki-e/install-action@v2.26.8 + uses: taiki-e/install-action@v2.26.12 with: tool: nextest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79c581b81..9af6d75f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: toolchain: ${{ matrix.version.version }} - name: Install cargo-hack and cargo-ci-cache-clean - uses: taiki-e/install-action@v2.26.8 + uses: taiki-e/install-action@v2.26.12 with: tool: cargo-hack,cargo-ci-cache-clean diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 9fef98dcd..180a9a0e0 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,7 +23,7 @@ jobs: components: llvm-tools-preview - name: Install cargo-llvm-cov - uses: taiki-e/install-action@v2.26.8 + uses: taiki-e/install-action@v2.26.12 with: tool: cargo-llvm-cov diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 502bfeb61..bb03acce2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -82,7 +82,7 @@ jobs: toolchain: nightly-2023-08-25 - name: Install cargo-public-api - uses: taiki-e/install-action@v2.26.8 + uses: taiki-e/install-action@v2.26.12 with: tool: cargo-public-api