diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d54fa2f..1dd593f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,6 +16,10 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable - name: Build run: cargo build --verbose - name: Run tests diff --git a/Cargo.lock b/Cargo.lock index d36b597..c7b04a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,6 +389,26 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "dashmap" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -707,6 +727,7 @@ dependencies = [ "axum", "bytes", "clap", + "dashmap", "futures", "http-body-util", "hyper", diff --git a/Cargo.toml b/Cargo.toml index f2935cc..4fc6a69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ tracing = "0.1.40" hyper-util = { version = "0.1.7", features = ["tokio"] } native-tls = { version = "0.2.12", features = ["alpn"] } thiserror = "1.0.62" +dashmap = "6.0.1" [dev-dependencies] axum = { version = "0.7.2", features = ["http2"] } diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/src/tls.rs b/src/tls.rs index 627dcb8..786aa5b 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,9 +1,22 @@ +use std::{borrow::BorrowMut, sync::LazyLock}; + +use dashmap::{try_result::TryResult, DashMap}; +use rustls::ServerConfig; + +static SERVER_CONFIG_CACHE: LazyLock), rustls::ServerConfig>> = LazyLock::new(|| DashMap::new()); + pub fn server_config( host: String, root_cert: &rcgen::CertifiedKey, h2: bool, ) -> Result { - let mut cert_params = rcgen::CertificateParams::new(vec![host]).unwrap(); + + if let TryResult::Present(config) = SERVER_CONFIG_CACHE.try_get(&(host.clone(), root_cert.key_pair.serialize_der())) { + let mut config = config.clone(); + return Ok(maybe_h2_config(&mut config, h2).to_owned()); + } + + let mut cert_params = rcgen::CertificateParams::new(vec![host.clone()]).unwrap(); cert_params .key_usages .push(rcgen::KeyUsagePurpose::DigitalSignature); @@ -29,11 +42,17 @@ pub fn server_config( )), ); + if let Ok(config) = &config { + SERVER_CONFIG_CACHE.insert((host, root_cert.key_pair.serialize_der()), config.clone()); + } + + config.map(|mut config| maybe_h2_config(config.borrow_mut(), h2).to_owned()) +} + +fn maybe_h2_config(config: &mut ServerConfig, h2: bool) -> &ServerConfig { if h2 { - config.map(|mut server_config| { - server_config.alpn_protocols = vec!["h2".into(), "http/1.1".into()]; - server_config - }) + config.alpn_protocols = vec!["h2".into(), "http/1.1".into()]; + config } else { config }