use super::STATIC_TABLE;
use crate::{
KnownHeaderName as K,
headers::{
entry_name::{EntryName, PseudoHeaderName as P},
static_hit::StaticHit,
},
};
pub(in crate::headers) const fn static_lookup_name(name: &EntryName) -> Option<&'static [u8]> {
match name {
EntryName::Pseudo(P::Authority) => Some(&[1]),
EntryName::Pseudo(P::Method) => Some(&[2, 3]),
EntryName::Pseudo(P::Path) => Some(&[4, 5]),
EntryName::Pseudo(P::Scheme) => Some(&[6, 7]),
EntryName::Pseudo(P::Status) => Some(&[8, 9, 10, 11, 12, 13, 14]),
EntryName::Known(K::AcceptCharset) => Some(&[15]),
EntryName::Known(K::AcceptEncoding) => Some(&[16]),
EntryName::Known(K::AcceptLanguage) => Some(&[17]),
EntryName::Known(K::AcceptRanges) => Some(&[18]),
EntryName::Known(K::Accept) => Some(&[19]),
EntryName::Known(K::AccessControlAllowOrigin) => Some(&[20]),
EntryName::Known(K::Age) => Some(&[21]),
EntryName::Known(K::Allow) => Some(&[22]),
EntryName::Known(K::Authorization) => Some(&[23]),
EntryName::Known(K::CacheControl) => Some(&[24]),
EntryName::Known(K::ContentDisposition) => Some(&[25]),
EntryName::Known(K::ContentEncoding) => Some(&[26]),
EntryName::Known(K::ContentLanguage) => Some(&[27]),
EntryName::Known(K::ContentLength) => Some(&[28]),
EntryName::Known(K::ContentLocation) => Some(&[29]),
EntryName::Known(K::ContentRange) => Some(&[30]),
EntryName::Known(K::ContentType) => Some(&[31]),
EntryName::Known(K::Cookie) => Some(&[32]),
EntryName::Known(K::Date) => Some(&[33]),
EntryName::Known(K::Etag) => Some(&[34]),
EntryName::Known(K::Expect) => Some(&[35]),
EntryName::Known(K::Expires) => Some(&[36]),
EntryName::Known(K::From) => Some(&[37]),
EntryName::Known(K::Host) => Some(&[38]),
EntryName::Known(K::IfMatch) => Some(&[39]),
EntryName::Known(K::IfModifiedSince) => Some(&[40]),
EntryName::Known(K::IfNoneMatch) => Some(&[41]),
EntryName::Known(K::IfRange) => Some(&[42]),
EntryName::Known(K::IfUnmodifiedSince) => Some(&[43]),
EntryName::Known(K::LastModified) => Some(&[44]),
EntryName::Known(K::Link) => Some(&[45]),
EntryName::Known(K::Location) => Some(&[46]),
EntryName::Known(K::MaxForwards) => Some(&[47]),
EntryName::Known(K::ProxyAuthenticate) => Some(&[48]),
EntryName::Known(K::ProxyAuthorization) => Some(&[49]),
EntryName::Known(K::Range) => Some(&[50]),
EntryName::Known(K::Referer) => Some(&[51]),
EntryName::Known(K::Refresh) => Some(&[52]),
EntryName::Known(K::RetryAfter) => Some(&[53]),
EntryName::Known(K::Server) => Some(&[54]),
EntryName::Known(K::SetCookie) => Some(&[55]),
EntryName::Known(K::StrictTransportSecurity) => Some(&[56]),
EntryName::Known(K::TransferEncoding) => Some(&[57]),
EntryName::Known(K::UserAgent) => Some(&[58]),
EntryName::Known(K::Vary) => Some(&[59]),
EntryName::Known(K::Via) => Some(&[60]),
EntryName::Known(K::WwwAuthenticate) => Some(&[61]),
_ => None,
}
}
pub(in crate::headers) fn static_table_lookup(name: &EntryName, value: &[u8]) -> StaticHit {
let Some(indices) = static_lookup_name(name) else {
return StaticHit::None;
};
for &i in indices {
if STATIC_TABLE[(i - 1) as usize].1.as_bytes() == value {
return StaticHit::Full(i);
}
}
StaticHit::Name(indices[0])
}
#[cfg(test)]
mod tests {
use super::static_table_lookup;
use crate::headers::{
entry_name::EntryName,
hpack::static_table::{STATIC_TABLE, static_entry},
static_hit::StaticHit,
};
#[test]
fn lookup_matches_every_entry() {
for (i, (name, value)) in STATIC_TABLE.iter().enumerate() {
let wire_index = (i + 1) as u8;
let header_name = EntryName::from(*name);
let lookup = static_table_lookup(&header_name, value.as_bytes());
match lookup {
StaticHit::Full(found) => {
let (found_name, found_value) = *static_entry(found as usize).unwrap();
assert_eq!(EntryName::from(found_name), header_name);
assert_eq!(found_value.as_bytes(), value.as_bytes());
}
_ => panic!(
"expected Full for HPACK index {wire_index} ({}, {value:?}); got {lookup:?}",
name.as_str()
),
}
}
}
#[test]
fn name_match_for_unknown_value() {
let header_name = EntryName::from(STATIC_TABLE[27].0); let lookup = static_table_lookup(&header_name, b"99999");
let StaticHit::Name(found) = lookup else {
panic!("expected Name, got {lookup:?}");
};
let (found_name, _) = *static_entry(found as usize).unwrap();
assert_eq!(EntryName::from(found_name), header_name);
}
#[test]
fn no_match_for_unknown_name() {
let header_name = EntryName::try_from(b"x-custom".as_slice()).unwrap();
assert_eq!(static_table_lookup(&header_name, b"value"), StaticHit::None);
}
}