#![warn(missing_docs)]
use std::ops::Deref;
use crate::helpers::FromRequest;
use hyper::header::{HeaderName, HeaderValue};
use hyper::HeaderMap;
#[derive(Debug, Clone)]
pub struct RequestHeaders {
inner: HeaderMap,
}
impl RequestHeaders {
pub fn new() -> Self {
Self {
inner: HeaderMap::new(),
}
}
pub(crate) fn _with_capacity(capacity: usize) -> Self {
Self {
inner: HeaderMap::with_capacity(capacity),
}
}
pub(crate) fn from_header_map(map: HeaderMap) -> Self {
Self { inner: map }
}
pub fn insert<K, V>(&mut self, key: K, value: V)
where
K: AsRef<str>,
V: AsRef<str>,
{
if let (Ok(name), Ok(val)) = (
HeaderName::from_bytes(key.as_ref().as_bytes()),
HeaderValue::from_bytes(value.as_ref().as_bytes()),
) {
self.inner.insert(name, val);
}
}
pub fn append<K, V>(&mut self, key: K, value: V)
where
K: AsRef<str>,
V: AsRef<str>,
{
if let (Ok(name), Ok(val)) = (
HeaderName::from_bytes(key.as_ref().as_bytes()),
HeaderValue::from_bytes(value.as_ref().as_bytes()),
) {
self.inner.append(name, val);
}
}
pub fn get<K>(&self, key: K) -> Option<&str>
where
K: AsRef<str>,
{
let name = HeaderName::from_bytes(key.as_ref().as_bytes()).ok()?;
self.inner.get(&name)?.to_str().ok()
}
pub fn get_all<K>(&self, key: K) -> Vec<&str>
where
K: AsRef<str>,
{
if let Ok(name) = HeaderName::from_bytes(key.as_ref().as_bytes()) {
self.inner
.get_all(name)
.iter()
.filter_map(|v| v.to_str().ok())
.collect()
} else {
Vec::new()
}
}
pub fn contains_key<K>(&self, key: K) -> bool
where
K: AsRef<str>,
{
HeaderName::from_bytes(key.as_ref().as_bytes())
.ok()
.and_then(|name| self.inner.get(&name))
.is_some()
}
pub fn remove<K>(&mut self, key: K) -> Option<String>
where
K: AsRef<str>,
{
let name: HeaderName = HeaderName::from_bytes(key.as_ref().as_bytes()).ok()?;
self.inner.remove(&name)?.to_str().ok().map(String::from)
}
pub fn content_type(&self) -> Option<&str> {
self.get("content-type")
}
pub fn authorization(&self) -> Option<&str> {
self.get("authorization")
}
pub fn user_agent(&self) -> Option<&str> {
self.get("user-agent")
}
pub fn accept(&self) -> Option<&str> {
self.get("accept")
}
pub fn host(&self) -> Option<&str> {
self.get("host")
}
pub fn x_forwarded_for(&self) -> Option<&str> {
self.get("x-forwarded-for")
}
pub fn accepts_json(&self) -> bool {
self.accept()
.map(|accept| accept.contains("application/json") || accept.contains("*/*"))
.unwrap_or(false)
}
pub fn accepts_html(&self) -> bool {
self.accept()
.map(|accept| accept.contains("text/html") || accept.contains("*/*"))
.unwrap_or(false)
}
pub fn keys(&self) -> impl Iterator<Item = &HeaderName> {
self.inner.keys()
}
pub fn len(&self) -> usize {
self.inner.keys().len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&HeaderName, &HeaderValue)> {
self.inner.iter()
}
pub fn iter_all(&self) -> impl Iterator<Item = (&HeaderName, &str)> {
self.inner
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k, val)))
}
pub fn as_header_map(&self) -> &HeaderMap {
&self.inner
}
pub fn into_header_map(self) -> HeaderMap {
self.inner
}
}
impl Default for RequestHeaders {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Display for RequestHeaders {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (key, value) in self.iter() {
writeln!(f, "{}: {:?}", key, value)?;
}
Ok(())
}
}
impl std::ops::Index<&str> for RequestHeaders {
type Output = str;
fn index(&self, key: &str) -> &Self::Output {
self.get(key)
.unwrap_or_else(|| panic!("Header '{}' not found", key))
}
}
impl From<HeaderMap> for RequestHeaders {
fn from(map: HeaderMap) -> Self {
Self::from_header_map(map)
}
}
impl From<RequestHeaders> for HeaderMap {
fn from(headers: RequestHeaders) -> Self {
headers.into_header_map()
}
}
pub struct Headers(RequestHeaders);
impl FromRequest for Headers {
type Error = String;
fn from_request(req: &super::HttpRequest) -> Result<Self, Self::Error> {
Ok(Self(req.headers.clone()))
}
}
impl Deref for Headers {
type Target = RequestHeaders;
fn deref(&self) -> &Self::Target {
&self.0
}
}