use std::any::Any;
use std::borrow::{Cow, ToOwned};
use std::iter::{FromIterator, IntoIterator};
use std::ops::{Deref, DerefMut};
use std::{mem, fmt};
use {httparse, traitobject};
use typeable::Typeable;
use unicase::UniCase;
use self::internals::{Item, VecMap, Entry};
use self::sealed::Sealed;
pub use self::shared::*;
pub use self::common::*;
mod common;
mod internals;
mod shared;
pub mod parsing;
type HeaderName = UniCase<CowStr>;
pub trait Header: Clone + Any + Send + Sync {
fn header_name() -> &'static str;
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Self>;
}
pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result;
#[doc(hidden)]
#[inline]
fn fmt_multi_header(&self, f: &mut MultilineFormatter) -> fmt::Result {
f.fmt_line(&FmtHeader(self))
}
}
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct MultilineFormatter<'a, 'b: 'a>(Multi<'a, 'b>);
enum Multi<'a, 'b: 'a> {
Line(&'a str, &'a mut fmt::Formatter<'b>),
Join(bool, &'a mut fmt::Formatter<'b>),
}
impl<'a, 'b> MultilineFormatter<'a, 'b> {
fn fmt_line(&mut self, line: &fmt::Display) -> fmt::Result {
use std::fmt::Write;
match self.0 {
Multi::Line(ref name, ref mut f) => {
try!(f.write_str(*name));
try!(f.write_str(": "));
try!(write!(NewlineReplacer(*f), "{}", line));
f.write_str("\r\n")
},
Multi::Join(ref mut first, ref mut f) => {
if !*first {
try!(f.write_str(", "));
} else {
*first = false;
}
write!(NewlineReplacer(*f), "{}", line)
}
}
}
}
struct FmtHeader<'a, H: ?Sized + 'a>(&'a H);
impl<'a, H: HeaderFormat + ?Sized + 'a> fmt::Display for FmtHeader<'a, H> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt_header(f)
}
}
struct ValueString<'a>(&'a Item);
impl<'a> fmt::Display for ValueString<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.write_h1(&mut MultilineFormatter(Multi::Join(true, f)))
}
}
struct NewlineReplacer<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);
impl<'a, 'b> fmt::Write for NewlineReplacer<'a, 'b> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let mut since = 0;
for (i, &byte) in s.as_bytes().iter().enumerate() {
if byte == b'\r' || byte == b'\n' {
try!(self.0.write_str(&s[since..i]));
try!(self.0.write_str(" "));
since = i + 1;
}
}
if since < s.len() {
self.0.write_str(&s[since..])
} else {
Ok(())
}
}
}
pub trait HeaderClone: Sealed {}
impl<T: Sealed> HeaderClone for T {}
mod sealed {
use super::HeaderFormat;
#[doc(hidden)]
pub trait Sealed {
#[doc(hidden)]
fn clone_box(&self) -> Box<HeaderFormat + Send + Sync>;
}
#[doc(hidden)]
impl<T: HeaderFormat + Clone> Sealed for T {
#[inline]
fn clone_box(&self) -> Box<HeaderFormat + Send + Sync> {
Box::new(self.clone())
}
}
}
impl HeaderFormat + Send + Sync {
#[inline]
unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
mem::transmute(traitobject::data(self))
}
#[inline]
unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
mem::transmute(traitobject::data_mut(self))
}
}
impl Clone for Box<HeaderFormat + Send + Sync> {
#[inline]
fn clone(&self) -> Box<HeaderFormat + Send + Sync> {
self.clone_box()
}
}
#[inline]
fn header_name<T: Header>() -> &'static str {
<T as Header>::header_name()
}
#[derive(Clone)]
pub struct Headers {
data: VecMap<HeaderName, Item>,
}
impl Headers {
pub fn new() -> Headers {
Headers {
data: VecMap::new()
}
}
#[doc(hidden)]
pub fn from_raw(raw: &[httparse::Header]) -> ::Result<Headers> {
let mut headers = Headers::new();
for header in raw {
trace!("raw header: {:?}={:?}", header.name, &header.value[..]);
let name = UniCase(CowStr(Cow::Owned(header.name.to_owned())));
let item = match headers.data.entry(name) {
Entry::Vacant(entry) => entry.insert(Item::new_raw(vec![])),
Entry::Occupied(entry) => entry.into_mut()
};
let trim = header.value.iter().rev().take_while(|&&x| x == b' ').count();
let value = &header.value[.. header.value.len() - trim];
item.raw_mut().push(value.to_vec());
}
Ok(headers)
}
pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value);
self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))),
Item::new_typed(Box::new(value)));
}
pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> {
self.data
.get(&UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))))
.map(Item::raw)
}
pub fn set_raw<K: Into<Cow<'static, str>>>(&mut self, name: K,
value: Vec<Vec<u8>>) {
let name = name.into();
trace!("Headers.set_raw( {:?}, {:?} )", name, value);
self.data.insert(UniCase(CowStr(name)), Item::new_raw(value));
}
pub fn append_raw<K: Into<Cow<'static, str>>>(&mut self, name: K, value: Vec<u8>) {
let name = name.into();
trace!("Headers.append_raw( {:?}, {:?} )", name, value);
let name = UniCase(CowStr(name));
if let Some(item) = self.data.get_mut(&name) {
item.raw_mut().push(value);
return;
}
self.data.insert(name, Item::new_raw(vec![value]));
}
pub fn remove_raw(&mut self, name: &str) {
trace!("Headers.remove_raw( {:?} )", name);
self.data.remove(
&UniCase(CowStr(Cow::Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))
);
}
pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::typed::<H>)
}
pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
.and_then(Item::typed_mut::<H>)
}
pub fn has<H: Header + HeaderFormat>(&self) -> bool {
self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>()))))
}
pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool {
trace!("Headers.remove( {:?} )", header_name::<H>());
self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some()
}
pub fn iter(&self) -> HeadersItems {
HeadersItems {
inner: self.data.iter()
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn clear(&mut self) {
self.data.clear()
}
}
impl PartialEq for Headers {
fn eq(&self, other: &Headers) -> bool {
if self.len() != other.len() {
return false;
}
for header in self.iter() {
match other.get_raw(header.name()) {
Some(val) if val == self.get_raw(header.name()).unwrap() => {},
_ => { return false; }
}
}
true
}
}
impl fmt::Display for Headers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for header in self.iter() {
try!(fmt::Display::fmt(&header, f));
}
Ok(())
}
}
impl fmt::Debug for Headers {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(f.write_str("Headers { "));
for header in self.iter() {
try!(write!(f, "{:?}, ", header));
}
try!(f.write_str("}"));
Ok(())
}
}
pub struct HeadersItems<'a> {
inner: ::std::slice::Iter<'a, (HeaderName, Item)>
}
impl<'a> Iterator for HeadersItems<'a> {
type Item = HeaderView<'a>;
fn next(&mut self) -> Option<HeaderView<'a>> {
self.inner.next().map(|&(ref k, ref v)| HeaderView(k, v))
}
}
pub struct HeaderView<'a>(&'a HeaderName, &'a Item);
impl<'a> HeaderView<'a> {
#[inline]
pub fn is<H: Header>(&self) -> bool {
UniCase(CowStr(Cow::Borrowed(header_name::<H>()))) == *self.0
}
#[inline]
pub fn name(&self) -> &'a str {
self.0.as_ref()
}
#[inline]
pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
self.1.typed::<H>()
}
#[inline]
pub fn value_string(&self) -> String {
ValueString(self.1).to_string()
}
}
impl<'a> fmt::Display for HeaderView<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.1.write_h1(&mut MultilineFormatter(Multi::Line(&self.0, f)))
}
}
impl<'a> fmt::Debug for HeaderView<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl<'a> Extend<HeaderView<'a>> for Headers {
fn extend<I: IntoIterator<Item=HeaderView<'a>>>(&mut self, iter: I) {
for header in iter {
self.data.insert((*header.0).clone(), (*header.1).clone());
}
}
}
impl<'a> FromIterator<HeaderView<'a>> for Headers {
fn from_iter<I: IntoIterator<Item=HeaderView<'a>>>(iter: I) -> Headers {
let mut headers = Headers::new();
headers.extend(iter);
headers
}
}
#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut multi = MultilineFormatter(Multi::Join(true, f));
self.fmt_multi_header(&mut multi)
}
}
#[deprecated(note="The semantics of formatting a HeaderFormat directly are not clear")]
pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H);
#[allow(deprecated)]
impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut multi = MultilineFormatter(Multi::Join(true, f));
self.0.fmt_multi_header(&mut multi)
}
}
#[allow(deprecated)]
impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
#[derive(Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
struct CowStr(Cow<'static, str>);
impl Deref for CowStr {
type Target = Cow<'static, str>;
fn deref(&self) -> &Cow<'static, str> {
&self.0
}
}
impl fmt::Debug for CowStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for CowStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl DerefMut for CowStr {
fn deref_mut(&mut self) -> &mut Cow<'static, str> {
&mut self.0
}
}
impl AsRef<str> for CowStr {
fn as_ref(&self) -> &str {
self
}
}
#[cfg(test)]
mod tests {
use std::fmt;
use mime::Mime;
use mime::TopLevel::Text;
use mime::SubLevel::Plain;
use super::{Headers, Header, HeaderFormat, ContentLength, ContentType,
Accept, Host, qitem};
use httparse;
#[cfg(feature = "nightly")]
use test::Bencher;
fn index_of(slice: &[u8], byte: u8) -> Option<usize> {
for (index, &b) in slice.iter().enumerate() {
if b == byte {
return Some(index);
}
}
None
}
macro_rules! raw {
($($line:expr),*) => ({
[$({
let line = $line;
let pos = index_of(line, b':').expect("raw splits on ':', not found");
httparse::Header {
name: ::std::str::from_utf8(&line[..pos]).unwrap(),
value: &line[pos + 2..]
}
}),*]
})
}
#[test]
fn test_from_raw() {
let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
assert_eq!(headers.get(), Some(&ContentLength(10)));
}
#[test]
fn test_content_type() {
let content_type = Header::parse_header([b"text/plain".to_vec()].as_ref());
assert_eq!(content_type.ok(), Some(ContentType(Mime(Text, Plain, vec![]))));
}
#[test]
fn test_accept() {
let text_plain = qitem(Mime(Text, Plain, vec![]));
let application_vendor = "application/vnd.github.v3.full+json; q=0.5".parse().unwrap();
let accept = Header::parse_header([b"text/plain".to_vec()].as_ref());
assert_eq!(accept.ok(), Some(Accept(vec![text_plain.clone()])));
let bytevec = [b"application/vnd.github.v3.full+json; q=0.5, text/plain".to_vec()];
let accept = Header::parse_header(bytevec.as_ref());
assert_eq!(accept.ok(), Some(Accept(vec![application_vendor, text_plain])));
}
#[derive(Clone, PartialEq, Debug)]
struct CrazyLength(Option<bool>, usize);
impl Header for CrazyLength {
fn header_name() -> &'static str {
"content-length"
}
fn parse_header(raw: &[Vec<u8>]) -> ::Result<CrazyLength> {
use std::str::from_utf8;
use std::str::FromStr;
if raw.len() != 1 {
return Err(::Error::Header);
}
match match from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
Ok(s) => FromStr::from_str(s).ok(),
Err(_) => None
}.map(|u| CrazyLength(Some(false), u)) {
Some(x) => Ok(x),
None => Err(::Error::Header),
}
}
}
impl HeaderFormat for CrazyLength {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
let CrazyLength(ref opt, ref value) = *self;
write!(f, "{:?}, {:?}", opt, value)
}
}
#[test]
fn test_different_structs_for_same_header() {
let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10)));
}
#[test]
fn test_trailing_whitespace() {
let headers = Headers::from_raw(&raw!(b"Content-Length: 10 ")).unwrap();
assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10)));
}
#[test]
fn test_multiple_reads() {
let headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
let ContentLength(one) = *headers.get::<ContentLength>().unwrap();
let ContentLength(two) = *headers.get::<ContentLength>().unwrap();
assert_eq!(one, two);
}
#[test]
fn test_different_reads() {
let headers = Headers::from_raw(
&raw!(b"Content-Length: 10", b"Content-Type: text/plain")).unwrap();
let ContentLength(_) = *headers.get::<ContentLength>().unwrap();
let ContentType(_) = *headers.get::<ContentType>().unwrap();
}
#[test]
fn test_get_mutable() {
let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
*headers.get_mut::<ContentLength>().unwrap() = ContentLength(20);
assert_eq!(headers.get_raw("content-length").unwrap(), &[b"20".to_vec()][..]);
assert_eq!(*headers.get::<ContentLength>().unwrap(), ContentLength(20));
}
#[test]
fn test_headers_fmt() {
let mut headers = Headers::new();
headers.set(ContentLength(15));
headers.set(Host { hostname: "foo.bar".to_owned(), port: None });
let s = headers.to_string();
assert!(s.contains("Host: foo.bar\r\n"));
assert!(s.contains("Content-Length: 15\r\n"));
}
#[test]
fn test_headers_fmt_raw() {
let mut headers = Headers::from_raw(&raw!(b"Content-Length: 10")).unwrap();
headers.set_raw("x-foo", vec![b"foo".to_vec(), b"bar".to_vec()]);
let s = headers.to_string();
assert_eq!(s, "Content-Length: 10\r\nx-foo: foo\r\nx-foo: bar\r\n");
}
#[test]
fn test_set_raw() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"20".to_vec()][..]);
assert_eq!(headers.get(), Some(&ContentLength(20)));
}
#[test]
fn test_append_raw() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
headers.append_raw("content-LENGTH", b"20".to_vec());
assert_eq!(headers.get_raw("Content-length").unwrap(), &[b"10".to_vec(), b"20".to_vec()][..]);
headers.append_raw("x-foo", b"bar".to_vec());
assert_eq!(headers.get_raw("x-foo"), Some(&[b"bar".to_vec()][..]));
}
#[test]
fn test_remove_raw() {
let mut headers = Headers::new();
headers.set_raw("content-LENGTH", vec![b"20".to_vec()]);
headers.remove_raw("content-LENGTH");
assert_eq!(headers.get_raw("Content-length"), None);
}
#[test]
fn test_len() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
assert_eq!(headers.len(), 1);
headers.set(ContentType(Mime(Text, Plain, vec![])));
assert_eq!(headers.len(), 2);
headers.set(ContentLength(20));
assert_eq!(headers.len(), 2);
}
#[test]
fn test_clear() {
let mut headers = Headers::new();
headers.set(ContentLength(10));
headers.set(ContentType(Mime(Text, Plain, vec![])));
assert_eq!(headers.len(), 2);
headers.clear();
assert_eq!(headers.len(), 0);
}
#[test]
fn test_iter() {
let mut headers = Headers::new();
headers.set(ContentLength(11));
for header in headers.iter() {
assert!(header.is::<ContentLength>());
assert_eq!(header.name(), <ContentLength as Header>::header_name());
assert_eq!(header.value(), Some(&ContentLength(11)));
assert_eq!(header.value_string(), "11".to_owned());
}
}
#[test]
fn test_header_view_value_string() {
let mut headers = Headers::new();
headers.set_raw("foo", vec![b"one".to_vec(), b"two".to_vec()]);
for header in headers.iter() {
assert_eq!(header.name(), "foo");
assert_eq!(header.value_string(), "one, two");
}
}
#[test]
fn test_eq() {
let mut headers1 = Headers::new();
let mut headers2 = Headers::new();
assert_eq!(headers1, headers2);
headers1.set(ContentLength(11));
headers2.set(Host {hostname: "foo.bar".to_owned(), port: None});
assert!(headers1 != headers2);
headers1 = Headers::new();
headers2 = Headers::new();
headers1.set(ContentLength(11));
headers2.set(ContentLength(11));
assert_eq!(headers1, headers2);
headers1.set(ContentLength(10));
assert!(headers1 != headers2);
headers1 = Headers::new();
headers2 = Headers::new();
headers1.set(Host { hostname: "foo.bar".to_owned(), port: None });
headers1.set(ContentLength(11));
headers2.set(ContentLength(11));
assert!(headers1 != headers2);
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_new(b: &mut Bencher) {
b.iter(|| {
let mut h = Headers::new();
h.set(ContentLength(11));
h
})
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_from_raw(b: &mut Bencher) {
let raw = raw!(b"Content-Length: 10");
b.iter(|| Headers::from_raw(&raw).unwrap())
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_get(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_get_miss(b: &mut Bencher) {
let headers = Headers::new();
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_set(b: &mut Bencher) {
let mut headers = Headers::new();
b.iter(|| headers.set(ContentLength(12)))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_has(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
b.iter(|| assert!(headers.has::<ContentLength>()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_view_is(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
let mut iter = headers.iter();
let view = iter.next().unwrap();
b.iter(|| assert!(view.is::<ContentLength>()))
}
#[cfg(feature = "nightly")]
#[bench]
fn bench_headers_fmt(b: &mut Bencher) {
let mut headers = Headers::new();
headers.set(ContentLength(11));
b.iter(|| headers.to_string())
}
}