/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::borrow::Cow;
/// Represents a header name that we know to be both valid and lowercase. /// Internally, this avoids allocating for headers that are constant strings, /// like the predefined ones in this crate, however even without that /// optimization, we would still likely have an equivalent of this for use /// as a case-insensitive string guaranteed to only have valid characters. #[derive(Debug, Clone, PartialEq, PartialOrd, Hash, Eq, Ord)] pubstruct HeaderName(pub(super) Cow<'static, str>);
/// Indicates an invalid header name. Note that we only emit /// this for response headers, for request headers, we panic /// instead. This is because it would likely come through as /// a network error if we emitted it for local headers, when /// it's actually a bug that we'd need to fix. #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)] #[error("Invalid header name: {0:?}")] pubstruct InvalidHeaderName(Cow<'static, str>);
fn validate_header(mut name: Cow<'static, str>) -> Result<HeaderName, InvalidHeaderName> { if name.len() == 0 { return Err(invalid_header_name(name));
} letmut need_lower_case = false; for b in name.bytes() { let validity = VALID_HEADER_LUT[b as usize]; if validity == 0 { return Err(invalid_header_name(name));
} if validity == 2 {
need_lower_case = true;
}
} if need_lower_case { // Only do this if needed, since it causes us to own the header.
name.to_mut().make_ascii_lowercase();
}
Ok(HeaderName(name))
}
impl HeaderName { /// Create a new header. In general you likely want to use `HeaderName::from(s)` /// instead for headers being specified locally (This will panic instead of /// returning a Result, since we have control over headers we specify locally, /// and want to know if we specify an illegal one). #[inline] pubfn new<S: Into<Cow<'static, str>>>(s: S) -> Result<Self, InvalidHeaderName> {
validate_header(s.into())
}
macro_rules! partialeq_boilerplate {
($T0:ty, $T1:ty) => { // This macro is used for items with and without lifetimes. #[allow(clippy::extra_unused_lifetimes)] impl<'a> PartialEq<$T0> for $T1 { fn eq(&self, other: &$T0) -> bool { // The &* should invoke Deref::deref if it exists, no-op otherwise.
(&*self).eq_ignore_ascii_case(&*other)
}
} #[allow(clippy::extra_unused_lifetimes)] impl<'a> PartialEq<$T1> for $T0 { fn eq(&self, other: &$T1) -> bool {
PartialEq::eq(other, self)
}
}
};
}
#[test] fn test_lut() { letmut expect = [0u8; 256]; for b in b'0'..=b'9' {
expect[b as usize] = 1;
} for b in b'a'..=b'z' {
expect[b as usize] = 1;
} for b in b'A'..=b'Z' {
expect[b as usize] = 2;
} for b in b"!#$%&'*+-.^_`|~" {
expect[*b as usize] = 1;
}
assert_eq!(&VALID_HEADER_LUT[..], &expect[..]);
} #[test] fn test_validate() {
assert!(validate_header("".into()).is_err());
assert!(validate_header(" foo ".into()).is_err());
assert!(validate_header("a=b".into()).is_err());
assert_eq!(
validate_header("content-type".into()),
Ok(HeaderName("content-type".into()))
);
assert_eq!(
validate_header("Content-Type".into()),
Ok(HeaderName("content-type".into()))
);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.