New HeaderMap type for grouping Headers.

This commit is contained in:
Sergio Benitez 2016-12-15 12:37:17 -08:00
parent d3e2d829c7
commit a73a082153
4 changed files with 86 additions and 31 deletions

View File

@ -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<T> From<T> for Header<'static> where T: HyperHeader + HyperHeaderFormat {
impl<T> From<T> 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<Cow<'h, str>, Vec<Cow<'h, str>>>
}
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<Item=&'a str> {
self.headers.get(name).into_iter().flat_map(|values| {
values.iter().map(|val| val.borrow())
})
}
#[inline(always)]
pub fn replace<'p: 'h, H: Into<Header<'p>>>(&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<Cow<'v, str>>)
where 'n: 'h, H: Into<Cow<'n, str>>
{
self.headers.insert(name.into(), values);
}
#[inline(always)]
pub fn add<'p: 'h, H: Into<Header<'p>>>(&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<Cow<'h, str>>)
where 'n:'h, H: Into<Cow<'n, str>>
{
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<Item=Header<'s>> {
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<Item=(Cow<'h, str>, Vec<Cow<'h, str>>)> {
self.headers.into_iter()
}
}

View File

@ -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};

View File

@ -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);
}
}

View File

@ -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<Status>,
headers: HashMap<Cow<'r, str>, Vec<Cow<'r, str>>>,
headers: HeaderMap<'r>,
body: Option<Body<Box<io::Read + 'r>>>,
}
@ -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<Item=Header<'a>> {
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<Item=&'h str> {
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<Header<'h>>>(&mut self, header: H) {
let header = header.into();
self.headers.insert(header.name, vec![header.value]);
pub fn set_header<'h: 'r, H: Into<Header<'h>>>(&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<Cow<'a, str>>, V: Into<Cow<'b, str>>
{
self.set_header(Header::new(name, value));
self.set_header(Header::new(name, value))
}
#[inline(always)]
pub fn adjoin_header<'h: 'r, H: Into<Header<'h>>>(&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);
}
}
}