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 e63821892..1a0437cbe 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
-        uses: taiki-e/install-action@v2.25.9
+      - name: Install cargo-hack and cargo-ci-cache-clean
+        uses: taiki-e/install-action@v2.26.12
         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,10 +71,8 @@ jobs:
           cargo test --lib --tests -p=actix-multipart --all-features
           cargo test --lib --tests -p=actix-web-actors --all-features
 
-      - name: Clear the cargo caches
-        run: |
-          cargo --locked install cargo-cache --version 0.8.3 --no-default-features --features ci-autoclean
-          cargo-cache
+      - name: CI cache clean
+        run: cargo-ci-cache-clean
 
   ci_feature_powerset_check:
     name: Verify Feature Combinations
@@ -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.25.9
+        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.25.9
+        uses: taiki-e/install-action@v2.26.12
         with:
           tool: nextest
 
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9dcd8fab9..915eb7eae 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,7 +26,7 @@ jobs:
           - { name: macOS, os: macos-latest, triple: x86_64-apple-darwin }
           - { name: Windows, os: windows-latest, triple: x86_64-pc-windows-msvc }
         version:
-          - { name: msrv, version: 1.68.0 }
+          - { name: msrv, version: 1.72.0 }
           - { name: stable, version: stable }
 
     name: ${{ matrix.target.name }} / ${{ matrix.version.name }}
@@ -37,29 +37,27 @@ 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
-        uses: taiki-e/install-action@v2.25.9
+      - name: Install cargo-hack and cargo-ci-cache-clean
+        uses: taiki-e/install-action@v2.26.12
         with:
-          tool: cargo-hack
+          tool: cargo-hack,cargo-ci-cache-clean
 
       - name: workaround MSRV issues
         if: matrix.version.name == 'msrv'
         run: |
-          cargo update -p=clap --precise=4.3.24
-          cargo update -p=clap_lex --precise=0.5.0
-          cargo update -p=anstyle --precise=1.0.2
+          cargo update -p=clap --precise=4.4.18
 
       - name: check minimal
         run: cargo ci-check-min
@@ -69,10 +67,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
@@ -81,10 +81,8 @@ jobs:
           cargo test --lib --tests -p=actix-multipart --all-features
           cargo test --lib --tests -p=actix-web-actors --all-features
 
-      - name: Clear the cargo caches
-        run: |
-          cargo --locked install cargo-cache --version 0.8.3 --no-default-features --features ci-autoclean
-          cargo-cache
+      - name: CI cache clean
+        run: cargo-ci-cache-clean
 
   io-uring:
     name: io-uring tests
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 2722da084..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.25.9
+        uses: taiki-e/install-action@v2.26.12
         with:
           tool: cargo-llvm-cov
 
@@ -31,7 +31,9 @@ jobs:
         run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json
 
       - name: Upload coverage to Codecov
-        uses: codecov/codecov-action@v3.1.4
+        uses: codecov/codecov-action@v4.0.1
         with:
           files: codecov.json
           fail_ci_if_error: true
+        env:
+          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index adcb257b5..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.24.1
+        uses: taiki-e/install-action@v2.26.12
         with:
           tool: cargo-public-api
 
diff --git a/Cargo.toml b/Cargo.toml
index 58fd96935..9efeda4d1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,7 +17,7 @@ members = [
 [workspace.package]
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.68"
+rust-version = "1.72"
 
 [profile.dev]
 # Disabling debug info speeds up builds a bunch and we don't rely on it for debugging that much.
diff --git a/actix-files/CHANGES.md b/actix-files/CHANGES.md
index 9aa62ff77..393e7b61a 100644
--- a/actix-files/CHANGES.md
+++ b/actix-files/CHANGES.md
@@ -2,6 +2,8 @@
 
 ## Unreleased
 
+- Minimum supported Rust version (MSRV) is now 1.72.
+
 ## 0.6.5
 
 - Fix handling of special characters in filenames.
diff --git a/actix-files/README.md b/actix-files/README.md
index df80e4047..a6b3f63c6 100644
--- a/actix-files/README.md
+++ b/actix-files/README.md
@@ -4,7 +4,7 @@
 
 [](https://crates.io/crates/actix-files)
 [](https://docs.rs/actix-files/0.6.5)
-
+
 
 
 [](https://deps.rs/crate/actix-files/0.6.5)
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-test/CHANGES.md b/actix-http-test/CHANGES.md
index 065141b20..4d133e3ec 100644
--- a/actix-http-test/CHANGES.md
+++ b/actix-http-test/CHANGES.md
@@ -2,6 +2,10 @@
 
 ## Unreleased
 
+- Minimum supported Rust version (MSRV) is now 1.72.
+
+## 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..ee242d1d5 100644
--- a/actix-http-test/README.md
+++ b/actix-http-test/README.md
@@ -5,17 +5,12 @@
 
 
 [](https://crates.io/crates/actix-http-test)
-[](https://docs.rs/actix-http-test/3.1.0)
-
+[](https://docs.rs/actix-http-test/3.2.0)
+
 
 
-[](https://deps.rs/crate/actix-http-test/3.1.0)
+[](https://deps.rs/crate/actix-http-test/3.2.0)
 [](https://crates.io/crates/actix-http-test)
 [](https://discord.gg/NWpN5mmg3x)
 
 
-
-## Documentation & Resources
-
-- [API Documentation](https://docs.rs/actix-http-test)
-- Minimum Supported Rust Version (MSRV): 1.68
diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md
index 994c91a83..fddd1c2c3 100644
--- a/actix-http/CHANGES.md
+++ b/actix-http/CHANGES.md
@@ -2,6 +2,18 @@
 
 ## Unreleased
 
+### Changed
+
+- Minimum supported Rust version (MSRV) is now 1.72.
+
+## 3.6.0
+
+### 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
 
 ### Fixed
diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml
index e7d50c313..e8f315cb9 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 ",
@@ -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,35 +121,40 @@ 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"
 criterion = { version = "0.5", features = ["html_reports"] }
+divan = "0.1.8"
 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"
 harness = false
 required-features = ["compress-brotli", "compress-gzip", "compress-zstd"]
+
+[[bench]]
+name = "date-formatting"
+harness = false
diff --git a/actix-http/README.md b/actix-http/README.md
index 9d80c10c4..3881b805d 100644
--- a/actix-http/README.md
+++ b/actix-http/README.md
@@ -5,21 +5,16 @@
 
 
 [](https://crates.io/crates/actix-http)
-[](https://docs.rs/actix-http/3.5.1)
-
+[](https://docs.rs/actix-http/3.6.0)
+
 
 
-[](https://deps.rs/crate/actix-http/3.5.1)
+[](https://deps.rs/crate/actix-http/3.6.0)
 [](https://crates.io/crates/actix-http)
 [](https://discord.gg/NWpN5mmg3x)
 
 
 
-## Documentation & Resources
-
-- [API Documentation](https://docs.rs/actix-http)
-- Minimum Supported Rust Version (MSRV): 1.68
-
 ## Examples
 
 ```rust
diff --git a/actix-http/benches/date-formatting.rs b/actix-http/benches/date-formatting.rs
new file mode 100644
index 000000000..26d0f3daa
--- /dev/null
+++ b/actix-http/benches/date-formatting.rs
@@ -0,0 +1,20 @@
+use std::time::SystemTime;
+
+use actix_http::header::HttpDate;
+use divan::{black_box, AllocProfiler, Bencher};
+
+#[global_allocator]
+static ALLOC: AllocProfiler = AllocProfiler::system();
+
+#[divan::bench]
+fn date_formatting(b: Bencher<'_, '_>) {
+    let now = SystemTime::now();
+
+    b.bench(|| {
+        black_box(HttpDate::from(black_box(now)).to_string());
+    })
+}
+
+fn main() {
+    divan::main();
+}
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/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/date.rs b/actix-http/src/date.rs
index 1358bbd8c..735dd9100 100644
--- a/actix-http/src/date.rs
+++ b/actix-http/src/date.rs
@@ -28,7 +28,7 @@ impl Date {
 
     fn update(&mut self) {
         self.pos = 0;
-        write!(self, "{}", httpdate::fmt_http_date(SystemTime::now())).unwrap();
+        write!(self, "{}", httpdate::HttpDate::from(SystemTime::now())).unwrap();
     }
 }
 
diff --git a/actix-http/src/h1/dispatcher.rs b/actix-http/src/h1/dispatcher.rs
index 270707807..a24a6bb07 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(),
@@ -703,7 +706,7 @@ where
 
                             req.head_mut().peer_addr = *this.peer_addr;
 
-                            req.conn_data = this.conn_data.as_ref().map(Rc::clone);
+                            req.conn_data = this.conn_data.clone();
 
                             match this.codec.message_type() {
                                 // request has no payload
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/dispatcher.rs b/actix-http/src/h2/dispatcher.rs
index 3e618820e..97ceb51e9 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},
@@ -127,7 +126,7 @@ where
                     head.headers = parts.headers.into();
                     head.peer_addr = this.peer_addr;
 
-                    req.conn_data = this.conn_data.as_ref().map(Rc::clone);
+                    req.conn_data = this.conn_data.clone();
 
                     let fut = this.flow.service.call(req);
                     let config = this.config.clone();
@@ -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()))?;
 
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/header/map.rs b/actix-http/src/header/map.rs
index d8a63b573..b86798a4c 100644
--- a/actix-http/src/header/map.rs
+++ b/actix-http/src/header/map.rs
@@ -650,6 +650,13 @@ impl From for http::HeaderMap {
     }
 }
 
+/// Convert our `&HeaderMap` to a `http::HeaderMap`.
+impl From<&HeaderMap> for http::HeaderMap {
+    fn from(map: &HeaderMap) -> Self {
+        map.to_owned().into()
+    }
+}
+
 /// Iterator over removed, owned values with the same associated name.
 ///
 /// Returned from methods that remove or replace items. See [`HeaderMap::insert`]
diff --git a/actix-http/src/header/shared/http_date.rs b/actix-http/src/header/shared/http_date.rs
index 21ed49f0c..bdfbc7051 100644
--- a/actix-http/src/header/shared/http_date.rs
+++ b/actix-http/src/header/shared/http_date.rs
@@ -24,8 +24,7 @@ impl FromStr for HttpDate {
 
 impl fmt::Display for HttpDate {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let date_str = httpdate::fmt_http_date(self.0);
-        f.write_str(&date_str)
+        httpdate::HttpDate::from(self.0).fmt(f)
     }
 }
 
@@ -37,7 +36,7 @@ impl TryIntoHeaderValue for HttpDate {
         let mut wrt = MutWriter(&mut buf);
 
         // unwrap: date output is known to be well formed and of known length
-        write!(wrt, "{}", httpdate::fmt_http_date(self.0)).unwrap();
+        write!(wrt, "{}", self).unwrap();
 
         HeaderValue::from_maybe_shared(buf.split().freeze())
     }
diff --git a/actix-http/src/header/utils.rs b/actix-http/src/header/utils.rs
index f4f34d347..caaab3b1e 100644
--- a/actix-http/src/header/utils.rs
+++ b/actix-http/src/header/utils.rs
@@ -80,18 +80,18 @@ mod tests {
 
     #[test]
     fn comma_delimited_parsing() {
-        let headers = vec![];
+        let headers = [];
         let res: Vec = from_comma_delimited(headers.iter()).unwrap();
         assert_eq!(res, vec![0; 0]);
 
-        let headers = vec![
+        let headers = [
             HeaderValue::from_static("1, 2"),
             HeaderValue::from_static("3,4"),
         ];
         let res: Vec = from_comma_delimited(headers.iter()).unwrap();
         assert_eq!(res, vec![1, 2, 3, 4]);
 
-        let headers = vec![
+        let headers = [
             HeaderValue::from_static(""),
             HeaderValue::from_static(","),
             HeaderValue::from_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/notify_on_drop.rs b/actix-http/src/notify_on_drop.rs
index 98544bb5d..95904b28e 100644
--- a/actix-http/src/notify_on_drop.rs
+++ b/actix-http/src/notify_on_drop.rs
@@ -5,7 +5,7 @@
 use std::cell::RefCell;
 
 thread_local! {
-    static NOTIFY_DROPPED: RefCell