diff --git a/lib/src/http/header.rs b/lib/src/http/header.rs index 5b380268..de364c3c 100644 --- a/lib/src/http/header.rs +++ b/lib/src/http/header.rs @@ -1,9 +1,9 @@ -use std::borrow::Cow; -use http::hyper::header::Header as HyperHeader; -use http::hyper::header::HeaderFormat as HyperHeaderFormat; -use http::hyper::header::HeaderFormatter as HyperHeaderFormatter; +use std::collections::HashMap; +use std::borrow::{Borrow, Cow}; use std::fmt; +use http::hyper::header as hyper; + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Header<'h> { pub name: Cow<'h, str>, @@ -29,9 +29,73 @@ impl<'h> fmt::Display for Header<'h> { } } -impl From for Header<'static> where T: HyperHeader + HyperHeaderFormat { +impl From for Header<'static> where T: hyper::Header + hyper::HeaderFormat { fn from(hyper_header: T) -> Header<'static> { - let formatter = HyperHeaderFormatter(&hyper_header); + let formatter = hyper::HeaderFormatter(&hyper_header); Header::new(T::header_name(), format!("{}", formatter)) } } + +pub struct HeaderMap<'h> { + headers: HashMap, Vec>> +} + +impl<'h> HeaderMap<'h> { + #[inline(always)] + pub fn new() -> HeaderMap<'h> { + HeaderMap { headers: HashMap::new() } + } + + #[inline(always)] + pub fn get<'a>(&'a self, name: &str) -> impl Iterator { + self.headers.get(name).into_iter().flat_map(|values| { + values.iter().map(|val| val.borrow()) + }) + } + + #[inline(always)] + pub fn replace<'p: 'h, H: Into>>(&mut self, header: H) -> bool { + let header = header.into(); + self.headers.insert(header.name, vec![header.value]).is_some() + } + + #[inline(always)] + pub fn replace_all<'n, 'v: 'h, H>(&mut self, name: H, values: Vec>) + where 'n: 'h, H: Into> + { + self.headers.insert(name.into(), values); + } + + #[inline(always)] + pub fn add<'p: 'h, H: Into>>(&mut self, header: H) { + let header = header.into(); + self.headers.entry(header.name).or_insert(vec![]).push(header.value); + } + + #[inline(always)] + pub fn add_all<'n, H>(&mut self, name: H, values: &mut Vec>) + where 'n:'h, H: Into> + { + self.headers.entry(name.into()).or_insert(vec![]).append(values) + } + + #[inline(always)] + pub fn remove(&mut self, name: &str) { + self.headers.remove(name); + } + + #[inline(always)] + pub fn iter<'s>(&'s self) -> impl Iterator> { + self.headers.iter().flat_map(|(key, values)| { + values.iter().map(move |val| { + Header::new(key.borrow(), val.borrow()) + }) + }) + } + + #[inline(always)] + pub fn into_iter<'s>(self) + -> impl Iterator, Vec>)> { + self.headers.into_iter() + } +} diff --git a/lib/src/http/mod.rs b/lib/src/http/mod.rs index 8ba88f6c..85288a4b 100644 --- a/lib/src/http/mod.rs +++ b/lib/src/http/mod.rs @@ -17,6 +17,6 @@ mod header; pub use self::method::Method; pub use self::content_type::ContentType; pub use self::status::Status; -pub use self::header::Header; +pub use self::header::{Header, HeaderMap}; pub use self::cookies::{Cookie, Cookies}; diff --git a/lib/src/response/named_file.rs b/lib/src/response/named_file.rs index e3d6b8c6..62ac856c 100644 --- a/lib/src/response/named_file.rs +++ b/lib/src/response/named_file.rs @@ -83,7 +83,7 @@ impl<'r> Responder<'r> for NamedFile { let ext_string = ext.to_string_lossy().to_lowercase(); let content_type = ContentType::from_extension(&ext_string); if !content_type.is_any() { - response.set_header(content_type) + response.set_header(content_type); } } diff --git a/lib/src/response/response.rs b/lib/src/response/response.rs index 673befb6..41aa8f0a 100644 --- a/lib/src/response/response.rs +++ b/lib/src/response/response.rs @@ -1,8 +1,7 @@ use std::{io, fmt, str}; -use std::borrow::{Borrow, Cow}; -use std::collections::HashMap; +use std::borrow::Cow; -use http::Header; +use http::{Header, HeaderMap}; use http::Status; pub const DEFAULT_CHUNK_SIZE: u64 = 4096; @@ -165,7 +164,7 @@ impl<'r> ResponseBuilder<'r> { /// Return type of a thing. pub struct Response<'r> { status: Option, - headers: HashMap, Vec>>, + headers: HeaderMap<'r>, body: Option>>, } @@ -174,7 +173,7 @@ impl<'r> Response<'r> { pub fn new() -> Response<'r> { Response { status: None, - headers: HashMap::new(), + headers: HeaderMap::new(), body: None, } } @@ -206,38 +205,30 @@ impl<'r> Response<'r> { #[inline(always)] pub fn headers<'a>(&'a self) -> impl Iterator> { - self.headers.iter().flat_map(|(key, values)| { - values.iter().map(move |val| { - Header::new(key.borrow(), val.borrow()) - }) - }) + self.headers.iter() } #[inline(always)] pub fn get_header_values<'h>(&'h self, name: &str) -> impl Iterator { - self.headers.get(name).into_iter().flat_map(|values| { - values.iter().map(|val| val.borrow()) - }) + self.headers.get(name) } #[inline(always)] - pub fn set_header<'h: 'r, H: Into>>(&mut self, header: H) { - let header = header.into(); - self.headers.insert(header.name, vec![header.value]); + pub fn set_header<'h: 'r, H: Into>>(&mut self, header: H) -> bool { + self.headers.replace(header) } #[inline(always)] - pub fn set_raw_header<'a: 'r, 'b: 'r, N, V>(&mut self, name: N, value: V) + pub fn set_raw_header<'a: 'r, 'b: 'r, N, V>(&mut self, name: N, value: V) -> bool where N: Into>, V: Into> { - self.set_header(Header::new(name, value)); + self.set_header(Header::new(name, value)) } #[inline(always)] pub fn adjoin_header<'h: 'r, H: Into>>(&mut self, header: H) { - let header = header.into(); - self.headers.entry(header.name).or_insert(vec![]).push(header.value); + self.headers.add(header) } #[inline(always)] @@ -248,7 +239,7 @@ impl<'r> Response<'r> { } #[inline(always)] - pub fn remove_header<'h>(&mut self, name: &'h str) { + pub fn remove_header(&mut self, name: &str) { self.headers.remove(name); } @@ -304,7 +295,7 @@ impl<'r> Response<'r> { } for (name, values) in other.headers.into_iter() { - self.headers.insert(name, values); + self.headers.replace_all(name, values); } } @@ -321,7 +312,7 @@ impl<'r> Response<'r> { } for (name, mut values) in other.headers.into_iter() { - self.headers.entry(name).or_insert(vec![]).append(&mut values) + self.headers.add_all(name, &mut values); } } }