Skip to content

Commit

Permalink
Rustls v0.22 support (#3275)
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede committed Feb 3, 2024
1 parent b1eb57a commit 2125aca
Show file tree
Hide file tree
Showing 24 changed files with 719 additions and 196 deletions.
4 changes: 2 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
23 changes: 10 additions & 13 deletions .github/workflows/ci-post-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]
with:
toolchain: ${{ matrix.version.version }}

- name: Install cargo-hack
- name: Install cargo-hack and cargo-ci-cache-clean
uses: taiki-e/[email protected]
with:
tool: cargo-hack
tool: cargo-hack,cargo-ci-cache-clean

- name: check minimal
run: cargo ci-check-min
Expand All @@ -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
Expand All @@ -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/[email protected]
with:
tool: cargo-ci-cache-clean

- name: CI cache clean
run: cargo-ci-cache-clean

Expand Down
23 changes: 10 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]
with:
toolchain: ${{ matrix.version.version }}

- name: Install cargo-hack
- name: Install cargo-hack and cargo-ci-cache-clean
uses: taiki-e/[email protected]
with:
tool: cargo-hack
tool: cargo-hack,cargo-ci-cache-clean

- name: workaround MSRV issues
if: matrix.version.name == 'msrv'
Expand All @@ -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
Expand All @@ -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/[email protected]
with:
tool: cargo-ci-cache-clean

- name: CI cache clean
run: cargo-ci-cache-clean

Expand Down
1 change: 1 addition & 0 deletions actix-files/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions actix-http/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 22 additions & 9 deletions actix-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"]
Expand Down Expand Up @@ -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 }
Expand All @@ -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"
Expand All @@ -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"
Expand Down
20 changes: 11 additions & 9 deletions actix-http/examples/tls_rustls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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::<Result<Vec<_>, _>>()
.unwrap();
let mut keys = rustls_pemfile::pkcs8_private_keys(key_file)
.collect::<Result<Vec<_>, _>>()
.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";
Expand Down
21 changes: 10 additions & 11 deletions actix-http/examples/ws.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -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::<Result<Vec<_>, _>>().unwrap();
let mut keys = pkcs8_private_keys(key_file)
.collect::<Result<Vec<_>, _>>()
.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());
Expand Down
65 changes: 63 additions & 2 deletions actix-http/src/h1/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _;
Expand Down Expand Up @@ -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 _;
Expand Down Expand Up @@ -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<S, B, X, U> H1Service<TlsStream<TcpStream>, S, B, X, U>
where
S: ServiceFactory<Request, Config = ()>,
S::Future: 'static,
S::Error: Into<Response<BoxBody>>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>,

B: MessageBody,

X: ServiceFactory<Request, Config = (), Response = Request>,
X::Future: 'static,
X::Error: Into<Response<BoxBody>>,
X::InitError: fmt::Debug,

U: ServiceFactory<
(Request, Framed<TlsStream<TcpStream>, Codec>),
Config = (),
Response = (),
>,
U::Future: 'static,
U::Error: fmt::Display + Into<Response<BoxBody>>,
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<io::Error, DispatchError>,
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<TcpStream>| {
let peer_addr = io.get_ref().0.peer_addr().ok();
(io, peer_addr)
})
.and_then(self.map_err(TlsError::Service))
}
}
}

impl<T, S, B, X, U> H1Service<T, S, B, X, U>
where
S: ServiceFactory<Request, Config = ()>,
Expand Down
Loading

0 comments on commit 2125aca

Please sign in to comment.