use std::{string::ToString, cmp::{PartialEq, Eq}, hash::{Hash, Hasher}}; use multimap::{MultiMap, IterAll}; use crate::{error::HTTPError, parse::{TryParse, Parse}}; #[derive(Debug, Clone, Eq)] pub struct HeaderName { inner: String } impl HeaderName { pub fn as_str(&self) -> &str { self.inner.as_ref() } } impl TryParse for HeaderName { fn try_parse(s: impl Into) -> Result { let name = s.into(); if name.len() < 1 { return Err(HTTPError::InvalidHeaderName(name)) } else { Ok(Self { inner: name }) } } } impl ToString for HeaderName { fn to_string(&self) -> String { self.inner.clone() } } impl PartialEq for HeaderName { fn eq(&self, other: &Self) -> bool { self.inner.eq_ignore_ascii_case(&other.inner) } } impl Hash for HeaderName { fn hash(&self, state: &mut H) { let mut hash: i32 = 0; for char in self.inner.chars() { let byte = char.to_ascii_lowercase() as u8; hash = hash ^ ((byte as i32) << 0); hash = hash ^ ((byte as i32) << 8); hash = hash ^ ((byte as i32) << 16); hash = hash ^ ((byte as i32) << 24); hash = hash % 16777213; } state.write_i32(hash); } } #[derive(Debug, Clone)] pub struct HeaderValue { inner: String } impl HeaderValue { pub fn as_str(&self) -> &str { self.inner.as_ref() } } impl Parse for HeaderValue { fn parse(value: impl Into) -> Self { Self { inner: value.into() } } } impl ToString for HeaderValue { fn to_string(&self) -> String { self.inner.clone() } } pub struct Header { pub name: HeaderName, pub value: HeaderValue } impl Header { pub fn new(name: impl Into, value: impl Into) -> Self { Self { name: name.into(), value: value.into() } } } impl TryParse for Header { fn try_parse(s: impl Into) -> Result { let s = s.into(); let Some(mid) = s.find(": ") else { return Err(HTTPError::InvalidHeader(s.to_string())) }; if mid == 0 || mid >= s.len() - 2 { return Err(HTTPError::InvalidHeader(s.to_string())) } let name = HeaderName::try_parse(&s[0..mid])?; let value = HeaderValue::parse(&s[(mid+2)..]); Ok(Header::new(name, value)) } } impl ToString for Header { fn to_string(&self) -> String { let mut s = String::new(); s.push_str(self.name.as_str()); s.push_str(": "); s.push_str(self.value.as_str()); s } } impl From<(H, V)> for Header where H: Into, V: Into { fn from(value: (H, V)) -> Self { Self { name: value.0.into(), value: value.1.into() } } } pub struct HeaderMap { inner: MultiMap } impl HeaderMap { pub fn new() -> Self { Self::with_headers(Vec::new()) } pub fn with_headers(headers: Vec
) -> Self { let mut inner = MultiMap::with_capacity(headers.len()); for header in headers { inner.insert(header.name.clone(), Header::new(header.name, header.value)); } Self { inner } } pub fn insert(&mut self, header: impl Into
) { let header = header.into(); self.inner.insert(header.name.clone(), Header::new(header.name, header.value)) } pub fn remove(&mut self, name: &HeaderName) -> Option> { self.inner.remove(name) } pub fn get(&mut self, name: &HeaderName) -> Option<&Vec
> { self.inner.get_vec(name) } pub fn iter(&self) -> HeaderMapIter { HeaderMapIter { inner: self.inner.iter_all() } } } pub struct HeaderMapIter<'i> { inner: IterAll<'i, HeaderName, Vec
> } impl<'i> Iterator for HeaderMapIter<'i> { type Item = &'i Vec
; fn next(&mut self) -> Option { match self.inner.next() { Some(h) => Some(h.1), None => None, } } }