From 1c60978a895d736c53025f2aab88340fb0b3e464 Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Thu, 3 Aug 2023 06:28:45 +0100
Subject: [PATCH 001/207] chore: move codecov file
---
codecov.yml => .codecov.yml | 0
actix-web/README.md | 15 ++++++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
rename codecov.yml => .codecov.yml (100%)
diff --git a/codecov.yml b/.codecov.yml
similarity index 100%
rename from codecov.yml
rename to .codecov.yml
diff --git a/actix-web/README.md b/actix-web/README.md
index 565f2b0f3..74b4924d4 100644
--- a/actix-web/README.md
+++ b/actix-web/README.md
@@ -5,7 +5,20 @@
-[](https://crates.io/crates/actix-web) [](https://docs.rs/actix-web/4.3.1)   [](https://deps.rs/crate/actix-web/4.3.1)
[](https://github.com/actix/actix-web/actions/workflows/ci.yml) [](https://codecov.io/gh/actix/actix-web)  [](https://discord.gg/NWpN5mmg3x)
+
+
+[](https://crates.io/crates/actix-web)
+[](https://docs.rs/actix-web/4.3.1)
+
+
+[](https://deps.rs/crate/actix-web/4.3.1)
+
+[](https://github.com/actix/actix-web/actions/workflows/ci.yml)
+[](https://codecov.io/gh/actix/actix-web)
+
+[](https://discord.gg/NWpN5mmg3x)
+
+
From 12dbda986ee89726d62edc609f7928307ce5390c Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Thu, 3 Aug 2023 06:54:50 +0100
Subject: [PATCH 002/207] test: fix test_h2_connection_drop spurious hang
fixes #3061
---
awc/src/client/connection.rs | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/awc/src/client/connection.rs b/awc/src/client/connection.rs
index 64075eae8..12d00914a 100644
--- a/awc/src/client/connection.rs
+++ b/awc/src/client/connection.rs
@@ -394,6 +394,8 @@ mod test {
#[actix_rt::test]
async fn test_h2_connection_drop() {
+ env_logger::try_init().ok();
+
let addr = "127.0.0.1:0".parse::().unwrap();
let listener = net::TcpListener::bind(addr).unwrap();
let local = listener.local_addr().unwrap();
@@ -428,11 +430,18 @@ mod test {
if this.start_from.elapsed() > Duration::from_secs(10) {
panic!("connection should be gone and can not be ready");
} else {
- let _ = this.interval.poll_tick(cx);
- Poll::Pending
+ match this.interval.poll_tick(cx) {
+ Poll::Ready(_) => {
+ // prevents spurious test hang
+ this.interval.reset();
+
+ Poll::Pending
+ }
+ Poll::Pending => Poll::Pending,
+ }
}
}
- Err(_) => Poll::Ready(()),
+ Err(err) => Poll::Ready(()),
}
}
}
From eaabe7e6869872384dcc6c85fe021f60b25f3f8a Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Thu, 3 Aug 2023 06:58:31 +0100
Subject: [PATCH 003/207] ci: reinstate coverage
---
.github/workflows/coverage.yml | 26 ++++++++++++++------------
.gitignore | 3 +++
awc/src/client/connection.rs | 2 +-
3 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 42f16450d..1e450d491 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -1,5 +1,3 @@
-# disabled because `cargo tarpaulin` currently segfaults
-
name: Coverage
on:
@@ -14,21 +12,25 @@ concurrency:
cancel-in-progress: true
jobs:
- # job currently (1st Feb 2022) segfaults
coverage:
- name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
+ - name: Install Rust
+ uses: actions-rust-lang/setup-rust-toolchain@v1.5.0
+ with:
+ components: llvm-tools-preview
- - uses: actions-rust-lang/setup-rust-toolchain@v1
- with: { toolchain: nightly }
+ - name: Install cargo-llvm-cov
+ uses: taiki-e/install-action@v2.13.4
+ with:
+ tool: cargo-llvm-cov
- - name: Generate coverage file
- run: |
- cargo install cargo-tarpaulin --vers "^0.13"
- cargo tarpaulin --workspace --features=rustls,openssl --out Xml --verbose
- - name: Upload to Codecov
+ - name: Generate code coverage
+ run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json
+
+ - name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.1.4
with:
- file: cobertura.xml
+ files: codecov.json
+ fail_ci_if_error: true
diff --git a/.gitignore b/.gitignore
index 543403267..91930acf8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,6 @@ guide/build/
# Configuration directory generated by VSCode
.vscode
+
+# code coverage
+/codecov.json
diff --git a/awc/src/client/connection.rs b/awc/src/client/connection.rs
index 12d00914a..5ed965bed 100644
--- a/awc/src/client/connection.rs
+++ b/awc/src/client/connection.rs
@@ -441,7 +441,7 @@ mod test {
}
}
}
- Err(err) => Poll::Ready(()),
+ Err(_) => Poll::Ready(()),
}
}
}
From d8df60bf4c04c3cbb99bcf19a141c202223e07ea Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Thu, 3 Aug 2023 07:03:42 +0100
Subject: [PATCH 004/207] build: add justfile
---
.cargo/config.toml | 3 ---
.github/workflows/coverage.yml | 2 +-
justfile | 11 +++++++++++
3 files changed, 12 insertions(+), 4 deletions(-)
create mode 100644 justfile
diff --git a/.cargo/config.toml b/.cargo/config.toml
index deb300749..931b20b2c 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -12,6 +12,3 @@ ci-check-all-feature-powerset-linux="hack --workspace --feature-powerset --skip=
# testing
ci-doctest-default = "test --workspace --doc --no-fail-fast -- --nocapture"
ci-doctest = "test --workspace --all-features --doc --no-fail-fast -- --nocapture"
-
-# compile docs as docs.rs would
-# RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 1e450d491..1feae0432 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -5,7 +5,7 @@ on:
branches: [master]
permissions:
- contents: read # to fetch code (actions/checkout)
+ contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/justfile b/justfile
new file mode 100644
index 000000000..f2e449d85
--- /dev/null
+++ b/justfile
@@ -0,0 +1,11 @@
+_list:
+ @just --list
+
+# Document crates in workspace.
+doc:
+ RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --features=rustls,openssl
+
+# Document crates in workspace and watch for changes.
+doc-watch:
+ RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --features=rustls,openssl --open
+ cargo watch -- RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc --no-deps --workspace --features=rustls,openssl
From 14355b94421716dd2a70b7bfe1d863f80c768be8 Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Sat, 26 Aug 2023 18:19:32 +0100
Subject: [PATCH 005/207] ci: name msrv jobs (#3114)
---
.github/workflows/ci-post-merge.yml | 8 ++++----
.github/workflows/ci.yml | 17 +++++++++--------
.gitignore | 1 +
3 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/.github/workflows/ci-post-merge.yml b/.github/workflows/ci-post-merge.yml
index 06669e31e..5460eeec4 100644
--- a/.github/workflows/ci-post-merge.yml
+++ b/.github/workflows/ci-post-merge.yml
@@ -22,9 +22,9 @@ jobs:
- { name: macOS, os: macos-latest, triple: x86_64-apple-darwin }
- { name: Windows, os: windows-latest, triple: x86_64-pc-windows-msvc }
version:
- - nightly
+ - { name: nightly, version: nightly }
- name: ${{ matrix.target.name }} / ${{ matrix.version }}
+ name: ${{ matrix.target.name }} / ${{ matrix.version.name }}
runs-on: ${{ matrix.target.os }}
steps:
@@ -39,10 +39,10 @@ jobs:
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
- - name: Install Rust (${{ matrix.version }})
+ - name: Install Rust (${{ matrix.version.name }})
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
- toolchain: ${{ matrix.version }}
+ toolchain: ${{ matrix.version.version }}
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f073f6afe..f12202017 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,10 +26,10 @@ jobs:
- { name: macOS, os: macos-latest, triple: x86_64-apple-darwin }
- { name: Windows, os: windows-latest, triple: x86_64-pc-windows-msvc }
version:
- - 1.68.0 # MSRV
- - stable
+ - { name: msrv, version: 1.68.0 }
+ - { name: stable, version: stable }
- name: ${{ matrix.target.name }} / ${{ matrix.version }}
+ name: ${{ matrix.target.name }} / ${{ matrix.version.name }}
runs-on: ${{ matrix.target.os }}
steps:
@@ -44,17 +44,18 @@ jobs:
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
- - name: Install Rust (${{ matrix.version }})
+ - name: Install Rust (${{ matrix.version.name }})
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
- toolchain: ${{ matrix.version }}
+ toolchain: ${{ matrix.version.version }}
- name: Install cargo-hack
uses: taiki-e/install-action@cargo-hack
- # - name: workaround MSRV issues
- # if: matrix.version != 'stable'
- # run: |
+ - name: workaround MSRV issues
+ if: matrix.version.name != 'stable'
+ run: |
+ cargo update -p=clap --precise=4.3.24
- name: check minimal
run: cargo ci-check-min
diff --git a/.gitignore b/.gitignore
index 91930acf8..48ccccb92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,5 @@ guide/build/
.vscode
# code coverage
+/lcov.info
/codecov.json
From 55c15f5bbf96518738bb440cea84c25551296bec Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Sun, 27 Aug 2023 00:07:11 +0100
Subject: [PATCH 006/207] minimum viable rustls v0.21 support (#3112)
---
.github/workflows/ci.yml | 1 +
Cargo.toml | 5 ++
actix-http/CHANGES.md | 2 +
actix-http/Cargo.toml | 29 ++++++---
actix-http/examples/tls_rustls.rs | 73 +++++++++++++++++++++
actix-http/examples/ws.rs | 6 +-
actix-http/src/h1/service.rs | 69 ++++++++++++++++++--
actix-http/src/h2/service.rs | 57 +++++++++++++++-
actix-http/src/lib.rs | 2 +-
actix-http/src/service.rs | 104 ++++++++++++++++++++++++++++--
actix-http/tests/test_rustls.rs | 45 +++++++------
actix-web/Cargo.toml | 3 +-
awc/Cargo.toml | 2 +-
13 files changed, 350 insertions(+), 48 deletions(-)
create mode 100644 actix-http/examples/tls_rustls.rs
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f12202017..fdd6f0f9a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -56,6 +56,7 @@ jobs:
if: matrix.version.name != 'stable'
run: |
cargo update -p=clap --precise=4.3.24
+ cargo update -p=clap_lex --precise=0.5.0
- name: check minimal
run: cargo ci-check-min
diff --git a/Cargo.toml b/Cargo.toml
index 65e3c6ae8..58fd96935 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,11 @@ members = [
"awc",
]
+[workspace.package]
+license = "MIT OR Apache-2.0"
+edition = "2021"
+rust-version = "1.68"
+
[profile.dev]
# Disabling debug info speeds up builds a bunch and we don't rely on it for debugging that much.
debug = 0
diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md
index 0dedd2c74..7078adb7e 100644
--- a/actix-http/CHANGES.md
+++ b/actix-http/CHANGES.md
@@ -4,6 +4,8 @@
### Added
+- Add `rustls-0_20` crate feature.
+- Add `{H1Service, H2Service, HttpService}::rustls_021()` and `HttpService::rustls_021_with_config()` service constructors.
- Add `body::to_body_limit()` function.
- Add `body::BodyLimitExceeded` error type.
diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml
index 6909b785f..61fba4bce 100644
--- a/actix-http/Cargo.toml
+++ b/actix-http/Cargo.toml
@@ -15,8 +15,9 @@ categories = [
"web-programming::http-server",
"web-programming::websocket",
]
-license = "MIT OR Apache-2.0"
-edition = "2021"
+license.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[package.metadata.docs.rs]
# features that docs.rs will build with
@@ -43,15 +44,21 @@ ws = [
# TLS via OpenSSL
openssl = ["actix-tls/accept", "actix-tls/openssl"]
-# TLS via Rustls
-rustls = ["actix-tls/accept", "actix-tls/rustls"]
+# TLS via Rustls v0.20
+rustls = ["rustls-0_20"]
+
+# TLS via Rustls v0.20
+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"]
# Compression codecs
compress-brotli = ["__compress", "brotli"]
compress-gzip = ["__compress", "flate2"]
compress-zstd = ["__compress", "zstd"]
-# Internal (PRIVATE!) features used to aid testing and cheking feature status.
+# Internal (PRIVATE!) features used to aid testing and checking feature status.
# Don't rely on these whatsoever. They are semver-exempt and may disappear at anytime.
__compress = []
@@ -91,7 +98,7 @@ rand = { version = "0.8", optional = true }
sha1 = { version = "0.10", optional = true }
# openssl/rustls
-actix-tls = { version = "3", default-features = false, optional = true }
+actix-tls = { version = "3.1", default-features = false, optional = true }
# compress-*
brotli = { version = "3.3.3", optional = true }
@@ -101,7 +108,7 @@ zstd = { version = "0.12", optional = true }
[dev-dependencies]
actix-http-test = { version = "3", features = ["openssl"] }
actix-server = "2"
-actix-tls = { version = "3", features = ["openssl"] }
+actix-tls = { version = "3.1", features = ["openssl"] }
actix-web = "4"
async-stream = "0.3"
@@ -118,12 +125,16 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
static_assertions = "1"
tls-openssl = { package = "openssl", version = "0.10.55" }
-tls-rustls = { package = "rustls", version = "0.20" }
+tls-rustls_021 = { package = "rustls", version = "0.21" }
tokio = { version = "1.24.2", features = ["net", "rt", "macros"] }
[[example]]
name = "ws"
-required-features = ["ws", "rustls"]
+required-features = ["ws", "rustls-0_21"]
+
+[[example]]
+name = "tls_rustls"
+required-features = ["http2", "rustls-0_21"]
[[bench]]
name = "response-body-compression"
diff --git a/actix-http/examples/tls_rustls.rs b/actix-http/examples/tls_rustls.rs
new file mode 100644
index 000000000..fbb55c6a4
--- /dev/null
+++ b/actix-http/examples/tls_rustls.rs
@@ -0,0 +1,73 @@
+//! Demonstrates TLS configuration (via Rustls) for HTTP/1.1 and HTTP/2 connections.
+//!
+//! Test using cURL:
+//!
+//! ```console
+//! $ curl --insecure https://127.0.0.1:8443
+//! Hello World!
+//! Protocol: HTTP/2.0
+//!
+//! $ curl --insecure --http1.1 https://127.0.0.1:8443
+//! Hello World!
+//! Protocol: HTTP/1.1
+//! ```
+
+extern crate tls_rustls_021 as rustls;
+
+use std::io;
+
+use actix_http::{Error, HttpService, Request, Response};
+use actix_utils::future::ok;
+
+#[actix_rt::main]
+async fn main() -> io::Result<()> {
+ env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
+
+ tracing::info!("starting HTTP server at https://127.0.0.1:8443");
+
+ actix_server::Server::build()
+ .bind("echo", ("127.0.0.1", 8443), || {
+ HttpService::build()
+ .finish(|req: Request| {
+ let body = format!(
+ "Hello World!\n\
+ Protocol: {:?}",
+ req.head().version
+ );
+ ok::<_, Error>(Response::ok().set_body(body))
+ })
+ .rustls_021(rustls_config())
+ })?
+ .run()
+ .await
+}
+
+fn rustls_config() -> rustls::ServerConfig {
+ let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap();
+ let cert_file = cert.serialize_pem().unwrap();
+ let key_file = cert.serialize_private_key_pem();
+
+ let cert_file = &mut io::BufReader::new(cert_file.as_bytes());
+ 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();
+
+ let mut config = rustls::ServerConfig::builder()
+ .with_safe_defaults()
+ .with_no_client_auth()
+ .with_single_cert(cert_chain, rustls::PrivateKey(keys.remove(0)))
+ .unwrap();
+
+ const H1_ALPN: &[u8] = b"http/1.1";
+ const H2_ALPN: &[u8] = b"h2";
+
+ config.alpn_protocols.push(H2_ALPN.to_vec());
+ config.alpn_protocols.push(H1_ALPN.to_vec());
+
+ config
+}
diff --git a/actix-http/examples/ws.rs b/actix-http/examples/ws.rs
index 6af6d5095..241175ae2 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 as rustls;
+extern crate tls_rustls_021 as rustls;
use std::{
io,
@@ -28,7 +28,9 @@ async fn main() -> io::Result<()> {
HttpService::build().h1(handler).tcp()
})?
.bind("tls", ("127.0.0.1", 8443), || {
- HttpService::build().finish(handler).rustls(tls_config())
+ HttpService::build()
+ .finish(handler)
+ .rustls_021(tls_config())
})?
.run()
.await
diff --git a/actix-http/src/h1/service.rs b/actix-http/src/h1/service.rs
index fbda7138e..3b27e3db5 100644
--- a/actix-http/src/h1/service.rs
+++ b/actix-http/src/h1/service.rs
@@ -152,13 +152,13 @@ mod openssl {
}
}
-#[cfg(feature = "rustls")]
-mod rustls {
+#[cfg(feature = "rustls-0_20")]
+mod rustls_020 {
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,
};
@@ -188,7 +188,7 @@ mod rustls {
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,
@@ -213,6 +213,67 @@ mod rustls {
}
}
+#[cfg(feature = "rustls-0_21")]
+mod rustls_021 {
+ use std::io;
+
+ use actix_service::ServiceFactoryExt as _;
+ use actix_tls::accept::{
+ rustls_0_21::{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.21 based service.
+ pub fn rustls_021(
+ 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 3f742135a..0ae7ea682 100644
--- a/actix-http/src/h2/service.rs
+++ b/actix-http/src/h2/service.rs
@@ -140,8 +140,8 @@ mod openssl {
}
}
-#[cfg(feature = "rustls")]
-mod rustls {
+#[cfg(feature = "rustls-0_20")]
+mod rustls_020 {
use std::io;
use actix_service::ServiceFactoryExt as _;
@@ -162,7 +162,7 @@ mod rustls {
B: MessageBody + 'static,
{
- /// Create Rustls based service.
+ /// Create Rustls v0.20 based service.
pub fn rustls(
self,
mut config: ServerConfig,
@@ -191,6 +191,57 @@ mod rustls {
}
}
+#[cfg(feature = "rustls-0_21")]
+mod rustls_021 {
+ use std::io;
+
+ use actix_service::ServiceFactoryExt as _;
+ use actix_tls::accept::{
+ rustls_0_21::{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.21 based service.
+ pub fn rustls_021(
+ 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 8b755f2f4..382295fbc 100644
--- a/actix-http/src/lib.rs
+++ b/actix-http/src/lib.rs
@@ -58,7 +58,7 @@ pub mod ws;
#[allow(deprecated)]
pub use self::payload::PayloadStream;
-#[cfg(any(feature = "openssl", feature = "rustls"))]
+#[cfg(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21"))]
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 e118d8361..bb0fda8c4 100644
--- a/actix-http/src/service.rs
+++ b/actix-http/src/service.rs
@@ -241,13 +241,13 @@ where
}
/// Configuration options used when accepting TLS connection.
-#[cfg(any(feature = "openssl", feature = "rustls"))]
+#[cfg(any(feature = "openssl", feature = "rustls-0_20", feature = "rustls-0_21"))]
#[derive(Debug, Default)]
pub struct TlsAcceptorConfig {
pub(crate) handshake_timeout: Option,
}
-#[cfg(any(feature = "openssl", feature = "rustls"))]
+#[cfg(any(feature = "openssl", feature = "rustls", feature = "rustls-0_21"))]
impl TlsAcceptorConfig {
/// Set TLS handshake timeout duration.
pub fn handshake_timeout(self, dur: std::time::Duration) -> Self {
@@ -352,8 +352,8 @@ mod openssl {
}
}
-#[cfg(feature = "rustls")]
-mod rustls {
+#[cfg(feature = "rustls-0_20")]
+mod rustls_020 {
use std::io;
use actix_service::ServiceFactoryExt as _;
@@ -448,6 +448,102 @@ mod rustls {
}
}
+#[cfg(feature = "rustls-0_21")]
+mod rustls_021 {
+ use std::io;
+
+ use actix_service::ServiceFactoryExt as _;
+ use actix_tls::accept::{
+ rustls_0_21::{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 based service.
+ pub fn rustls_021(
+ self,
+ config: ServerConfig,
+ ) -> impl ServiceFactory<
+ TcpStream,
+ Config = (),
+ Response = (),
+ Error = TlsError,
+ InitError = (),
+ > {
+ self.rustls_021_with_config(config, TlsAcceptorConfig::default())
+ }
+
+ /// Create Rustls based service with custom TLS acceptor configuration.
+ pub fn rustls_021_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 3d9a39cbd..c94e579e5 100644
--- a/actix-http/tests/test_rustls.rs
+++ b/actix-http/tests/test_rustls.rs
@@ -1,7 +1,6 @@
-#![cfg(feature = "rustls")]
-#![allow(clippy::uninlined_format_args)]
+#![cfg(feature = "rustls-0_21")]
-extern crate tls_rustls as rustls;
+extern crate tls_rustls_021 as rustls;
use std::{
convert::Infallible,
@@ -21,7 +20,7 @@ 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::webpki_roots_cert_store;
+use actix_tls::connect::rustls_0_21::webpki_roots_cert_store;
use actix_utils::future::{err, ok, poll_fn};
use bytes::{Bytes, BytesMut};
use derive_more::{Display, Error};
@@ -110,7 +109,7 @@ async fn h1() -> io::Result<()> {
let srv = test_server(move || {
HttpService::build()
.h1(|_| ok::<_, Error>(Response::ok()))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -124,7 +123,7 @@ async fn h2() -> io::Result<()> {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, Error>(Response::ok()))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -142,7 +141,7 @@ async fn h1_1() -> io::Result<()> {
assert_eq!(req.version(), Version::HTTP_11);
ok::<_, Error>(Response::ok())
})
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -160,7 +159,7 @@ async fn h2_1() -> io::Result<()> {
assert_eq!(req.version(), Version::HTTP_2);
ok::<_, Error>(Response::ok())
})
- .rustls_with_config(
+ .rustls_021_with_config(
tls_config(),
TlsAcceptorConfig::default().handshake_timeout(Duration::from_secs(5)),
)
@@ -181,7 +180,7 @@ async fn h2_body1() -> io::Result<()> {
let body = load_body(req.take_payload()).await?;
Ok::<_, Error>(Response::ok().set_body(body))
})
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -207,7 +206,7 @@ async fn h2_content_length() {
];
ok::<_, Infallible>(Response::new(statuses[indx]))
})
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -279,7 +278,7 @@ async fn h2_headers() {
}
ok::<_, Infallible>(config.body(data.clone()))
})
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -318,7 +317,7 @@ async fn h2_body2() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, Infallible>(Response::ok().set_body(STR)))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -335,7 +334,7 @@ async fn h2_head_empty() {
let mut srv = test_server(move || {
HttpService::build()
.finish(|_| ok::<_, Infallible>(Response::ok().set_body(STR)))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -361,7 +360,7 @@ async fn h2_head_binary() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, Infallible>(Response::ok().set_body(STR)))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -386,7 +385,7 @@ async fn h2_head_binary2() {
let srv = test_server(move || {
HttpService::build()
.h2(|_| ok::<_, Infallible>(Response::ok().set_body(STR)))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -412,7 +411,7 @@ async fn h2_body_length() {
Response::ok().set_body(SizedStream::new(STR.len() as u64, body)),
)
})
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -436,7 +435,7 @@ async fn h2_body_chunked_explicit() {
.body(BodyStream::new(body)),
)
})
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -465,7 +464,7 @@ async fn h2_response_http_error_handling() {
)
}))
}))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -495,7 +494,7 @@ async fn h2_service_error() {
let mut srv = test_server(move || {
HttpService::build()
.h2(|_| err::, _>(BadRequest))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -512,7 +511,7 @@ async fn h1_service_error() {
let mut srv = test_server(move || {
HttpService::build()
.h1(|_| err::, _>(BadRequest))
- .rustls(tls_config())
+ .rustls_021(tls_config())
})
.await;
@@ -535,7 +534,7 @@ async fn alpn_h1() -> io::Result<()> {
config.alpn_protocols.push(CUSTOM_ALPN_PROTOCOL.to_vec());
HttpService::build()
.h1(|_| ok::<_, Error>(Response::ok()))
- .rustls(config)
+ .rustls_021(config)
})
.await;
@@ -557,7 +556,7 @@ async fn alpn_h2() -> io::Result<()> {
config.alpn_protocols.push(CUSTOM_ALPN_PROTOCOL.to_vec());
HttpService::build()
.h2(|_| ok::<_, Error>(Response::ok()))
- .rustls(config)
+ .rustls_021(config)
})
.await;
@@ -583,7 +582,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(config)
+ .rustls_021(config)
})
.await;
diff --git a/actix-web/Cargo.toml b/actix-web/Cargo.toml
index 4322fb871..7dbaa2a29 100644
--- a/actix-web/Cargo.toml
+++ b/actix-web/Cargo.toml
@@ -16,7 +16,8 @@ categories = [
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-web.git"
license = "MIT OR Apache-2.0"
-edition = "2021"
+edition.workspace = true
+rust-version.workspace = true
[package.metadata.docs.rs]
# features that docs.rs will build with
diff --git a/awc/Cargo.toml b/awc/Cargo.toml
index daec84ab9..2a09a52c4 100644
--- a/awc/Cargo.toml
+++ b/awc/Cargo.toml
@@ -45,7 +45,7 @@ cookies = ["cookie"]
# trust-dns as dns resolver
trust-dns = ["trust-dns-resolver"]
-# Internal (PRIVATE!) features used to aid testing and cheking feature status.
+# Internal (PRIVATE!) features used to aid testing and checking feature status.
# Don't rely on these whatsoever. They may disappear at anytime.
__compress = []
From cbf5e948db5237c0efc359fac19e116ec4c1d561 Mon Sep 17 00:00:00 2001
From: Wyatt Herkamp
Date: Sun, 27 Aug 2023 18:47:05 -0400
Subject: [PATCH 007/207] Implement Deserialize and Default for actix_web::Data
(#3109)
* Implement Default and Deserialize for Data
* FMT
* Change Log
* tweak changelog
* chore: whitespace
---------
Co-authored-by: Rob Ede
---
actix-web/CHANGES.md | 2 ++
actix-web/src/data.rs | 19 ++++++++++++++++++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md
index 518a02507..97bf4ed04 100644
--- a/actix-web/CHANGES.md
+++ b/actix-web/CHANGES.md
@@ -9,6 +9,8 @@
- Add `web::Payload::to_bytes[_limited]()` helper methods.
- Add missing constructors on `HttpResponse` for several status codes.
- Add `http::header::ContentLength` typed header.
+- Implement `Default` for `web::Data`.
+- Implement `serde::Deserialize` for `web::Data`.
### Changed
diff --git a/actix-web/src/data.rs b/actix-web/src/data.rs
index 423dd598c..449a24a64 100644
--- a/actix-web/src/data.rs
+++ b/actix-web/src/data.rs
@@ -3,7 +3,7 @@ use std::{any::type_name, ops::Deref, sync::Arc};
use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
-use serde::Serialize;
+use serde::{de, Serialize};
use crate::{dev::Payload, error, Error, FromRequest, HttpRequest};
@@ -128,6 +128,12 @@ impl From> for Data {
}
}
+impl Default for Data {
+ fn default() -> Self {
+ Data::new(T::default())
+ }
+}
+
impl Serialize for Data
where
T: Serialize,
@@ -139,6 +145,17 @@ where
self.0.serialize(serializer)
}
}
+impl<'de, T> de::Deserialize<'de> for Data
+where
+ T: de::Deserialize<'de>,
+{
+ fn deserialize(deserializer: D) -> Result
+ where
+ D: de::Deserializer<'de>,
+ {
+ Ok(Data::new(T::deserialize(deserializer)?))
+ }
+}
impl FromRequest for Data {
type Error = Error;
From 905c30af865924b8853eba7149cddd17c114d171 Mon Sep 17 00:00:00 2001
From: Rob Ede
Date: Tue, 29 Aug 2023 01:11:11 +0100
Subject: [PATCH 008/207] Actix Web Rustls v0.21 support (#3116)
---
.github/workflows/ci.yml | 2 +-
.github/workflows/clippy-fmt.yml | 5 +-
actix-files/src/lib.rs | 7 +-
actix-http/Cargo.toml | 2 +-
actix-http/src/h1/payload.rs | 7 +-
actix-http/src/service.rs | 2 +-
actix-multipart/src/server.rs | 4 +-
actix-router/benches/quoter.rs | 9 +-
actix-router/src/url.rs | 8 +-
actix-test/CHANGES.md | 4 +-
actix-test/Cargo.toml | 13 ++-
actix-test/src/lib.rs | 75 +++++++++++---
actix-web/CHANGES.md | 4 +-
actix-web/Cargo.toml | 16 +--
actix-web/src/app_service.rs | 6 +-
actix-web/src/handler.rs | 2 +-
actix-web/src/route.rs | 2 +-
actix-web/src/server.rs | 126 +++++++++++++++++++----
actix-web/tests/test_server.rs | 6 +-
awc/CHANGES.md | 2 +
awc/Cargo.toml | 27 +++--
awc/src/client/connector.rs | 167 ++++++++++++++++++++++++-------
awc/tests/test_rustls_client.rs | 10 +-
23 files changed, 382 insertions(+), 124 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fdd6f0f9a..f071ec8f3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -69,7 +69,7 @@ jobs:
run: |
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,openssl -- --skip=test_reading_deflate_encoding_large_random_rustls
+ 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-codegen --all-features
cargo test --lib --tests -p=awc --all-features
cargo test --lib --tests -p=actix-http-test --all-features
diff --git a/.github/workflows/clippy-fmt.yml b/.github/workflows/clippy-fmt.yml
index 109165ce0..25c05bcbc 100644
--- a/.github/workflows/clippy-fmt.yml
+++ b/.github/workflows/clippy-fmt.yml
@@ -39,7 +39,7 @@ jobs:
with:
reporter: 'github-pr-check'
github_token: ${{ secrets.GITHUB_TOKEN }}
- clippy_flags: --workspace --all-features --tests --examples --bins -- -Dclippy::todo
+ clippy_flags: --workspace --all-features --tests --examples --bins -- -Dclippy::todo -Aunknown_lints
lint-docs:
runs-on: ubuntu-latest
@@ -63,8 +63,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions-rust-lang/setup-rust-toolchain@v1
- # temp: unpin once https://github.com/rust-lang/rust/issues/113152 is fixed
- with: { toolchain: nightly-2023-06-28 }
+ with: { toolchain: nightly-2023-08-25 }
- uses: taiki-e/cache-cargo-install-action@v1
with: { tool: cargo-public-api }
diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs
index 1d8609889..7871905f6 100644
--- a/actix-files/src/lib.rs
+++ b/actix-files/src/lib.rs
@@ -66,6 +66,7 @@ type PathFilter = dyn Fn(&Path, &RequestHead) -> bool;
#[cfg(test)]
mod tests {
use std::{
+ fmt::Write as _,
fs::{self},
ops::Add,
time::{Duration, SystemTime},
@@ -848,8 +849,10 @@ mod tests {
let filename_encoded = filename
.as_bytes()
.iter()
- .map(|c| format!("%{:02X}", c))
- .collect::();
+ .fold(String::new(), |mut buf, c| {
+ write!(&mut buf, "%{:02X}", c).unwrap();
+ buf
+ });
std::fs::File::create(tmpdir.path().join(filename)).unwrap();
let srv = test::init_service(App::new().service(Files::new("", tmpdir.path()))).await;
diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml
index 61fba4bce..6aaaecfd4 100644
--- a/actix-http/Cargo.toml
+++ b/actix-http/Cargo.toml
@@ -21,7 +21,7 @@ rust-version.workspace = true
[package.metadata.docs.rs]
# features that docs.rs will build with
-features = ["http2", "ws", "openssl", "rustls", "compress-brotli", "compress-gzip", "compress-zstd"]
+features = ["http2", "ws", "openssl", "rustls-0_20", "rustls-0_21", "compress-brotli", "compress-gzip", "compress-zstd"]
[lib]
name = "actix_http"
diff --git a/actix-http/src/h1/payload.rs b/actix-http/src/h1/payload.rs
index 1ed785a1b..2ad3a14a3 100644
--- a/actix-http/src/h1/payload.rs
+++ b/actix-http/src/h1/payload.rs
@@ -117,6 +117,7 @@ impl PayloadSender {
}
}
+ #[allow(clippy::needless_pass_by_ref_mut)]
#[inline]
pub fn need_read(&self, cx: &mut Context<'_>) -> PayloadStatus {
// we check need_read only if Payload (other side) is alive,
@@ -174,7 +175,7 @@ impl Inner {
/// Register future waiting data from payload.
/// Waker would be used in `Inner::wake`
- fn register(&mut self, cx: &mut Context<'_>) {
+ fn register(&mut self, cx: &Context<'_>) {
if self
.task
.as_ref()
@@ -186,7 +187,7 @@ impl Inner {
// Register future feeding data to payload.
/// Waker would be used in `Inner::wake_io`
- fn register_io(&mut self, cx: &mut Context<'_>) {
+ fn register_io(&mut self, cx: &Context<'_>) {
if self
.io_task
.as_ref()
@@ -221,7 +222,7 @@ impl Inner {
fn poll_next(
mut self: Pin<&mut Self>,
- cx: &mut Context<'_>,
+ cx: &Context<'_>,
) -> Poll