use crate::errors::ParseError;
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
#[repr(transparent)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ElifHeaderName(axum::http::HeaderName);
impl ElifHeaderName {
pub fn from_str(name: &str) -> Result<Self, ParseError> {
axum::http::HeaderName::from_str(name)
.map(Self)
.map_err(ParseError::from)
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
pub(crate) fn to_axum(&self) -> &axum::http::HeaderName {
&self.0
}
}
impl FromStr for ElifHeaderName {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
<ElifHeaderName>::from_str(s)
}
}
impl fmt::Display for ElifHeaderName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[repr(transparent)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ElifHeaderValue(axum::http::HeaderValue);
impl ElifHeaderValue {
pub fn from_str(value: &str) -> Result<Self, ParseError> {
axum::http::HeaderValue::from_str(value)
.map(Self)
.map_err(ParseError::from)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
axum::http::HeaderValue::from_bytes(bytes)
.map(Self)
.map_err(ParseError::from)
}
pub fn from_static(value: &'static str) -> Self {
Self(axum::http::HeaderValue::from_static(value))
}
pub fn to_str(&self) -> Result<&str, ParseError> {
self.0.to_str().map_err(ParseError::from)
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
pub(crate) fn to_axum(&self) -> &axum::http::HeaderValue {
&self.0
}
}
impl FromStr for ElifHeaderValue {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
<ElifHeaderValue>::from_str(s)
}
}
impl fmt::Display for ElifHeaderValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.to_str() {
Ok(s) => write!(f, "{}", s),
Err(_) => write!(f, "<invalid UTF-8>"),
}
}
}
#[derive(Debug, Clone)]
pub struct ElifHeaderMap(axum::http::HeaderMap);
impl ElifHeaderMap {
pub fn new() -> Self {
Self(axum::http::HeaderMap::new())
}
pub fn insert(
&mut self,
name: ElifHeaderName,
value: ElifHeaderValue,
) -> Option<ElifHeaderValue> {
self.0.insert(name.0, value.0).map(ElifHeaderValue)
}
pub fn append(&mut self, name: ElifHeaderName, value: ElifHeaderValue) -> bool {
self.0.append(name.0, value.0)
}
pub fn get(&self, name: &ElifHeaderName) -> Option<&ElifHeaderValue> {
unsafe { std::mem::transmute(self.0.get(&name.0)) }
}
pub fn get_str(&self, name: &str) -> Option<&ElifHeaderValue> {
if let Ok(header_name) = ElifHeaderName::from_str(name) {
self.get(&header_name)
} else {
None
}
}
pub fn remove(&mut self, name: &ElifHeaderName) -> Option<ElifHeaderValue> {
self.0.remove(&name.0).map(ElifHeaderValue)
}
pub fn contains_key(&self, name: &ElifHeaderName) -> bool {
self.0.contains_key(&name.0)
}
pub fn contains_key_str(&self, name: &str) -> bool {
if let Ok(header_name) = ElifHeaderName::from_str(name) {
self.contains_key(&header_name)
} else {
false
}
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn iter(&self) -> impl Iterator<Item = (&ElifHeaderName, &ElifHeaderValue)> {
self.0.iter().map(|(k, v)| {
unsafe { (std::mem::transmute(k), std::mem::transmute(v)) }
})
}
pub fn keys(&self) -> impl Iterator<Item = &ElifHeaderName> {
self.0.keys().map(|k| {
unsafe { std::mem::transmute(k) }
})
}
pub fn values(&self) -> impl Iterator<Item = &ElifHeaderValue> {
self.0.values().map(|v| {
unsafe { std::mem::transmute(v) }
})
}
pub fn add_header(&mut self, name: &str, value: &str) -> Result<(), String> {
if let Ok(header_name) = ElifHeaderName::from_str(name) {
if let Ok(header_value) = ElifHeaderValue::from_str(value) {
self.insert(header_name, header_value);
Ok(())
} else {
Err("Invalid header value".to_string())
}
} else {
Err("Invalid header name".to_string())
}
}
pub fn remove_header(&mut self, name: &str) -> Option<ElifHeaderValue> {
if let Ok(header_name) = ElifHeaderName::from_str(name) {
self.remove(&header_name)
} else {
None
}
}
pub fn to_hash_map(&self) -> HashMap<String, String> {
self.0
.iter()
.filter_map(|(k, v)| {
v.to_str()
.ok()
.map(|v| (k.as_str().to_string(), v.to_string()))
})
.collect()
}
pub(crate) fn from_axum(headers: axum::http::HeaderMap) -> Self {
Self(headers)
}
}
impl Default for ElifHeaderMap {
fn default() -> Self {
Self::new()
}
}
impl From<axum::http::HeaderMap> for ElifHeaderMap {
fn from(headers: axum::http::HeaderMap) -> Self {
Self::from_axum(headers)
}
}
pub mod header_names {
use super::ElifHeaderName;
use axum::http::header;
pub const AUTHORIZATION: ElifHeaderName = ElifHeaderName(header::AUTHORIZATION);
pub const CONTENT_TYPE: ElifHeaderName = ElifHeaderName(header::CONTENT_TYPE);
pub const CONTENT_LENGTH: ElifHeaderName = ElifHeaderName(header::CONTENT_LENGTH);
pub const ACCEPT: ElifHeaderName = ElifHeaderName(header::ACCEPT);
pub const CACHE_CONTROL: ElifHeaderName = ElifHeaderName(header::CACHE_CONTROL);
pub const ETAG: ElifHeaderName = ElifHeaderName(header::ETAG);
pub const IF_NONE_MATCH: ElifHeaderName = ElifHeaderName(header::IF_NONE_MATCH);
pub const LOCATION: ElifHeaderName = ElifHeaderName(header::LOCATION);
pub const SET_COOKIE: ElifHeaderName = ElifHeaderName(header::SET_COOKIE);
pub const COOKIE: ElifHeaderName = ElifHeaderName(header::COOKIE);
pub const USER_AGENT: ElifHeaderName = ElifHeaderName(header::USER_AGENT);
pub const REFERER: ElifHeaderName = ElifHeaderName(header::REFERER);
pub const ORIGIN: ElifHeaderName = ElifHeaderName(header::ORIGIN);
pub const ACCESS_CONTROL_ALLOW_ORIGIN: ElifHeaderName =
ElifHeaderName(header::ACCESS_CONTROL_ALLOW_ORIGIN);
pub const ACCESS_CONTROL_ALLOW_METHODS: ElifHeaderName =
ElifHeaderName(header::ACCESS_CONTROL_ALLOW_METHODS);
pub const ACCESS_CONTROL_ALLOW_HEADERS: ElifHeaderName =
ElifHeaderName(header::ACCESS_CONTROL_ALLOW_HEADERS);
pub const ACCESS_CONTROL_EXPOSE_HEADERS: ElifHeaderName =
ElifHeaderName(header::ACCESS_CONTROL_EXPOSE_HEADERS);
pub const ACCESS_CONTROL_ALLOW_CREDENTIALS: ElifHeaderName =
ElifHeaderName(header::ACCESS_CONTROL_ALLOW_CREDENTIALS);
pub const ACCESS_CONTROL_MAX_AGE: ElifHeaderName =
ElifHeaderName(header::ACCESS_CONTROL_MAX_AGE);
pub const CONTENT_SECURITY_POLICY: ElifHeaderName =
ElifHeaderName(header::CONTENT_SECURITY_POLICY);
pub const STRICT_TRANSPORT_SECURITY: ElifHeaderName =
ElifHeaderName(header::STRICT_TRANSPORT_SECURITY);
pub const X_FRAME_OPTIONS: ElifHeaderName = ElifHeaderName(header::X_FRAME_OPTIONS);
pub const X_CONTENT_TYPE_OPTIONS: ElifHeaderName =
ElifHeaderName(header::X_CONTENT_TYPE_OPTIONS);
pub const X_XSS_PROTECTION: ElifHeaderName = ElifHeaderName(header::X_XSS_PROTECTION);
pub const REFERRER_POLICY: ElifHeaderName = ElifHeaderName(header::REFERRER_POLICY);
}