no-std: limited_cache, sni_resolver support w/ hashbrown

This commit introduces a new `hash_map` module that exports `HashMap`
and `Entry` types when the `std` or `hashbrown` feature are enabled.

The underlying types are provided from `std::collections` for the
former, and the optional `hashbrown` dependency for the latter.

`LimitedCache` and `ResolvesServerCertUsingSni` both relied on
a `HashMap` implementation, and so were gated as
requiring the `std` feature previously. With the `hashbrown` feature
we can allow both when either `std` or `hashbrown` features are enabled,
supporting their use in no-std environments.
This commit is contained in:
Christian Poveda 2024-02-26 11:58:20 -05:00 committed by Daniel McCarney
parent bbc5ef742b
commit 8831ced544
6 changed files with 68 additions and 11 deletions

View File

@ -130,6 +130,10 @@ jobs:
run: cargo build --locked --no-default-features --target x86_64-unknown-none
working-directory: rustls
- name: cargo build (debug; no default features; no-std, hashbrown)
run: cargo build --locked --no-default-features --features hashbrown --target x86_64-unknown-none
working-directory: rustls
- name: cargo test (debug; default features)
run: cargo test --locked
working-directory: rustls

44
Cargo.lock generated
View File

@ -52,6 +52,18 @@ dependencies = [
"subtle",
]
[[package]]
name = "ahash"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@ -1126,6 +1138,15 @@ dependencies = [
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
@ -1331,7 +1352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.3",
]
[[package]]
@ -2157,6 +2178,7 @@ dependencies = [
"base64 0.22.0",
"bencher",
"env_logger",
"hashbrown 0.13.2",
"log",
"num-bigint",
"once_cell",
@ -3079,6 +3101,26 @@ dependencies = [
"time",
]
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.50",
]
[[package]]
name = "zeroize"
version = "1.7.0"

View File

@ -17,6 +17,7 @@ rustversion = { version = "1.0.6", optional = true }
[dependencies]
aws-lc-rs = { version = "1.6", optional = true, default-features = false, features = ["aws-lc-sys"] }
hashbrown = { version = "0.13", optional = true } # 0.14+ requires 1.63 MSRV
log = { version = "0.4.4", optional = true }
# remove once our MSRV is >= 1.70
once_cell = { version = "1.16", default-features = false, features = ["alloc", "race"] }

View File

@ -389,7 +389,7 @@ mod conn;
pub mod crypto;
mod error;
mod hash_hs;
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "hashbrown"))]
mod limited_cache;
mod rand;
mod record_layer;
@ -582,7 +582,7 @@ pub mod server {
pub use builder::WantsServerCert;
pub use handy::NoServerSessionStorage;
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "hashbrown"))]
pub use handy::ResolvesServerCertUsingSni;
#[cfg(feature = "std")]
pub use handy::ServerSessionMemoryCache;
@ -638,3 +638,16 @@ pub mod ticketer;
pub mod manual;
pub mod time_provider;
#[cfg(any(feature = "std", feature = "hashbrown"))]
mod hash_map {
#[cfg(feature = "std")]
pub(crate) use std::collections::hash_map::Entry;
#[cfg(feature = "std")]
pub(crate) use std::collections::HashMap;
#[cfg(all(not(feature = "std"), feature = "hashbrown"))]
pub(crate) use hashbrown::hash_map::Entry;
#[cfg(all(not(feature = "std"), feature = "hashbrown"))]
pub(crate) use hashbrown::HashMap;
}

View File

@ -1,8 +1,8 @@
use alloc::collections::VecDeque;
use core::borrow::Borrow;
use core::hash::Hash;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use crate::hash_map::{Entry, HashMap};
/// A HashMap-alike, which never gets larger than a specified
/// capacity, and evicts the oldest insertion to maintain this.
@ -19,7 +19,6 @@ pub(crate) struct LimitedCache<K: Clone + Hash + Eq, V> {
oldest: VecDeque<K>,
}
#[cfg(feature = "std")]
impl<K, V> LimitedCache<K, V>
where
K: Eq + Hash + Clone + core::fmt::Debug,
@ -211,7 +210,6 @@ mod tests {
}
}
#[cfg(feature = "std")]
#[test]
fn test_get_or_insert_default_and_edit_evicts_old_items_to_meet_capacity() {
let mut t = Test::new(3);
@ -240,7 +238,6 @@ mod tests {
assert_eq!(t.get("jkl"), None);
}
#[cfg(feature = "std")]
#[test]
fn test_get_or_insert_default_and_edit_edits_existing_item() {
let mut t = Test::new(3);

View File

@ -195,16 +195,16 @@ impl server::ResolvesServerCert for AlwaysResolvesChain {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "hashbrown"))]
mod sni_resolver {
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use core::fmt::Debug;
use std::collections::HashMap;
use pki_types::{DnsName, ServerName};
use crate::error::Error;
use crate::hash_map::HashMap;
use crate::server::ClientHello;
use crate::webpki::{verify_server_name, ParsedCertificate};
use crate::{server, sign};
@ -295,7 +295,7 @@ mod sni_resolver {
}
}
#[cfg(feature = "std")]
#[cfg(any(feature = "std", feature = "hashbrown"))]
pub use sni_resolver::ResolvesServerCertUsingSni;
#[cfg(test)]