use crate::{HeaderName, HeaderValue, WebError, WebResult};
use std::{
borrow::Borrow,
collections::HashMap,
fmt::Display,
hash::Hash,
ops::{Index, IndexMut},
};
use algorithm::buf::{Bt, BtMut};
#[derive(Debug, PartialEq, Eq)]
pub struct HeaderMap {
headers: Vec<(HeaderName, HeaderValue)>,
systems: HashMap<String, String>,
}
impl HeaderMap {
pub fn new() -> HeaderMap {
HeaderMap {
headers: Vec::new(),
systems: HashMap::new(),
}
}
pub fn iter(&self) -> std::slice::Iter<(HeaderName, HeaderValue)> {
self.headers.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<(HeaderName, HeaderValue)> {
self.headers.iter_mut()
}
pub fn push<T, V>(&mut self, name: T, value: V) -> Option<HeaderValue>
where
HeaderName: TryFrom<T>,
<HeaderName as TryFrom<T>>::Error: Into<WebError>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<WebError>,
{
let name = HeaderName::try_from(name).map_err(Into::into);
let value = HeaderValue::try_from(value).map_err(Into::into);
if name.is_err() || value.is_err() {
return None;
}
let (name, value) = (name.unwrap(), value.unwrap());
for v in self.headers.iter_mut() {
if v.0 == name {
v.1.push(value);
return None;
}
}
self.headers.push((name, value));
None
}
pub fn insert<T, V>(&mut self, name: T, value: V) -> Option<HeaderValue>
where
HeaderName: TryFrom<T>,
<HeaderName as TryFrom<T>>::Error: Into<WebError>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<WebError>,
{
let name = HeaderName::try_from(name).map_err(Into::into);
let value = HeaderValue::try_from(value).map_err(Into::into);
if name.is_err() || value.is_err() {
return None;
}
let (name, value) = (name.unwrap(), value.unwrap());
for v in self.headers.iter_mut() {
if v.0 == name {
v.1 = value;
return None;
}
}
self.headers.push((name, value));
None
}
pub fn remove<T: AsRef<[u8]>>(&mut self, name: &T) -> Option<HeaderValue> {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if v.0 == name.as_ref() {
return Some(self.headers.remove(i).1);
}
}
None
}
pub fn clear(&mut self) {
self.headers.clear()
}
pub fn contains<T: AsRef<[u8]>>(&self, name: &T) -> bool {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if &v.0 == &name.as_ref() {
return true;
}
}
false
}
pub fn get_value<T: AsRef<[u8]>>(&self, name: &T) -> &HeaderValue {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if &v.0 == &name.as_ref() {
return &v.1;
}
}
unreachable!()
}
pub fn get_mut_value<'a, T: AsRef<[u8]>>(&'a mut self, name: &T) -> &'a mut HeaderValue {
for v in self.headers.iter_mut() {
if &v.0 == &name.as_ref() {
return &mut v.1;
}
}
unreachable!()
}
pub fn get_option_value<T: AsRef<[u8]>>(&self, name: &T) -> Option<&HeaderValue> {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if v.0 == name.as_ref() {
return Some(&v.1);
}
}
None
}
pub fn get_str_value<T: AsRef<[u8]>>(&self, name: &T) -> Option<String> {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if v.0 == name.as_ref() {
return v.1.as_string();
}
}
None
}
pub fn is_contains<T: AsRef<[u8]>>(&self, name: &T, value: &[u8]) -> bool {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if v.0 == name.as_ref() {
return v.1.contains(value);
}
}
false
}
pub fn is_equal<T: AsRef<[u8]>>(&self, name: &T, value: &[u8]) -> bool {
for i in 0..self.headers.len() {
let v = &self.headers[i];
if v.0 == name.as_ref() {
return v.1.as_bytes() == value;
}
}
false
}
pub fn get_host(&self) -> Option<String> {
if let Some(value) = self.get_option_value(&HeaderName::HOST) {
value.try_into().ok()
} else if let Some(value) = self.get_option_value(&":authority") {
let value = TryInto::<String>::try_into(value).ok().unwrap();
if value.contains(":") {
let v: Vec<&str> = value.splitn(1, ':').collect();
return Some(v[0].to_string());
} else {
return Some(value);
}
} else {
None
}
}
pub fn get_referer(&self) -> Option<String> {
if let Some(value) = self.get_option_value(&HeaderName::REFERER) {
value.try_into().ok()
} else {
None
}
}
pub fn get_user_agent(&self) -> Option<String> {
if let Some(value) = self.get_option_value(&HeaderName::USER_AGENT) {
value.try_into().ok()
} else {
None
}
}
pub fn get_cookie(&self) -> Option<String> {
if let Some(value) = self.get_option_value(&HeaderName::COOKIE) {
value.try_into().ok()
} else {
None
}
}
pub fn get_body_len(&self) -> isize {
if let Some(value) = self.get_option_value(&HeaderName::CONTENT_LENGTH) {
value.try_into().unwrap_or(0)
} else {
0
}
}
pub fn is_keep_alive(&self) -> bool {
if let Some(value) = self.get_option_value(&HeaderName::CONNECTION) {
Self::contains_bytes(value.as_bytes(), b"Keep-Alive")
} else {
false
}
}
pub fn is_chunked(&self) -> bool {
if let Some(value) = self.get_option_value(&HeaderName::TRANSFER_ENCODING) {
Self::contains_bytes(value.as_bytes(), b"chunked")
} else {
false
}
}
pub fn get_upgrade_protocol(&self) -> Option<String> {
if let Some(value) = self.get_option_value(&HeaderName::CONNECTION) {
if !Self::contains_bytes(value.as_bytes(), b"Upgrade") {
return None;
}
} else {
return None;
}
if let Some(value) = self.get_option_value(&HeaderName::UPGRADE) {
return value.as_string();
} else {
return None;
}
}
pub fn len(&self) -> usize {
self.headers.len()
}
pub fn is_empty(&self) -> bool {
self.headers.len() == 0
}
pub fn system_insert(&mut self, key: String, value: String) {
self.systems.insert(key, value);
}
pub fn system_get<Q: ?Sized>(&self, key: &Q) -> Option<&String>
where
String: Borrow<Q>,
Q: Hash + Eq,
{
self.systems.get(key)
}
pub fn encode<B: Bt + BtMut>(&self, buffer: &mut B) -> WebResult<usize> {
let mut size = 0;
for value in self.iter() {
size += value.0.encode(buffer)?;
size += buffer.put_slice(": ".as_bytes());
size += value.1.encode(buffer)?;
size += buffer.put_slice("\r\n".as_bytes());
}
size += buffer.put_slice("\r\n".as_bytes());
Ok(size)
}
fn contains_bytes(src: &[u8], dst: &[u8]) -> bool {
if dst.len() > src.len() {
return false;
}
for i in 0..(src.len() - dst.len() + 1) {
if &src[i..(i + dst.len())] == dst {
return true;
}
}
false
}
}
impl Index<&'static str> for HeaderMap {
type Output = HeaderValue;
fn index(&self, index: &'static str) -> &Self::Output {
let name = HeaderName::Stand(index);
self.get_value(&name)
}
}
impl IndexMut<&'static str> for HeaderMap {
fn index_mut(&mut self, index: &'static str) -> &mut Self::Output {
let name = HeaderName::Stand(index);
if self.contains(&name) {
self.get_mut_value(&name)
} else {
self.insert(name, HeaderValue::Stand(""));
self.get_mut_value(&HeaderName::Stand(index))
}
}
}
impl IntoIterator for HeaderMap {
type Item = (HeaderName, HeaderValue);
type IntoIter = std::vec::IntoIter<(HeaderName, HeaderValue)>;
fn into_iter(self) -> Self::IntoIter {
self.headers.into_iter()
}
}
impl Clone for HeaderMap {
fn clone(&self) -> Self {
Self {
headers: self.headers.clone(),
systems: self.systems.clone(),
}
}
}
impl Display for HeaderMap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for v in &self.headers {
v.0.fmt(f)?;
f.write_str(": ")?;
v.1.fmt(f)?;
f.write_str("\r\n")?;
}
f.write_str("\r\n")
}
}