#![warn(missing_docs)]
mod frame;
mod http_types;
mod parse;
mod state;
#[cfg(test)]
mod tests;
#[cfg(feature = "tracing")]
macro_rules! trace_warn {
($($arg:tt)*) => { ::tracing::warn!($($arg)*) }
}
#[cfg(not(feature = "tracing"))]
macro_rules! trace_warn {
($($arg:tt)*) => {};
}
use std::{collections::HashMap, hash::Hash, sync::Mutex};
use dashmap::DashMap;
pub use frame::{CONNECTION_PREFACE, is_http2_preface, looks_like_http2_frame};
pub use http_types::{HttpRequest, HttpResponse};
pub use state::{
H2ConnectionState,
H2Limits,
ParseError,
ParseErrorKind,
ParsedH2Message,
StreamId,
TimestampNs,
};
pub(crate) use trace_warn;
pub struct H2SessionCache<K> {
connections: DashMap<K, Mutex<H2ConnectionState>>,
}
impl<K: Hash + Eq + Clone> H2SessionCache<K> {
pub fn new() -> Self {
Self {
connections: DashMap::new(),
}
}
pub fn parse(
&self,
key: K,
buffer: &[u8],
) -> Result<HashMap<StreamId, ParsedH2Message>, ParseError> {
self.connections
.entry(key.clone())
.or_insert_with(|| Mutex::new(H2ConnectionState::default()));
let entry = self.connections.get(&key).expect("entry was just ensured");
let mut state = entry.lock().unwrap_or_else(|e| e.into_inner());
parse::parse_frames_stateful(buffer, &mut state)
}
pub fn remove(&self, key: &K) -> Option<H2ConnectionState> {
self.connections
.remove(key)
.map(|(_, mutex)| mutex.into_inner().unwrap_or_else(|e| e.into_inner()))
}
pub fn contains(&self, key: &K) -> bool {
self.connections.contains_key(key)
}
pub fn len(&self) -> usize {
self.connections.len()
}
pub fn is_empty(&self) -> bool {
self.connections.is_empty()
}
}
impl<K: Hash + Eq + Clone> Default for H2SessionCache<K> {
fn default() -> Self {
Self::new()
}
}