//! Headers container, and common header fields. //! //! hyper has the opinion that Headers should be strongly-typed, because that's //! why we're using Rust in the first place. To set or get any header, an object //! must implement the `Header` trait from this module. Several common headers //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. use std::any::{Any, TypeId}; use std::borrow::Cow::{Borrowed, Owned}; use std::fmt; use std::raw::TraitObject; use std::str::from_utf8; use std::string::CowString; use std::collections::HashMap; use std::collections::hash_map::{Iter, Entry}; use std::iter::FromIterator; use std::borrow::IntoCow; use std::{mem, raw}; use mucell::MuCell; use uany::{UnsafeAnyExt}; use unicase::UniCase; use {http, HttpResult}; pub use self::shared::{Encoding, QualityItem, qitem}; pub use self::common::*; mod common; mod shared; pub mod parsing; type HeaderName = UniCase>; /// A trait for any object that will represent a header field and value. /// /// This trait represents the construction and identification of headers, /// and contains trait-object unsafe methods. pub trait Header: Clone + Any + Send + Sync { /// Returns the name of the header field this belongs to. /// /// This will become an associated constant once available. fn header_name() -> &'static str; /// Parse a header from a raw stream of bytes. /// /// It's possible that a request can include a header field more than once, /// and in that case, the slice will have a length greater than 1. However, /// it's not necessarily the case that a Header is *allowed* to have more /// than one field value. If that's the case, you **should** return `None` /// if `raw.len() > 1`. fn parse_header(raw: &[Vec]) -> Option; } /// A trait for any object that will represent a header field and value. /// /// This trait represents the formatting of a Header for output to a TcpStream. pub trait HeaderFormat: HeaderClone + Any + Send + Sync { /// Format a header to be output into a TcpStream. /// /// This method is not allowed to introduce an Err not produced /// by the passed-in Formatter. fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result; } #[doc(hidden)] pub trait HeaderClone { fn clone_box(&self) -> Box; } impl HeaderClone for T { #[inline] fn clone_box(&self) -> Box { Box::new(self.clone()) } } impl HeaderFormat { #[inline] fn is(&self) -> bool { self.get_type_id() == TypeId::of::() } } impl UnsafeAnyExt for HeaderFormat { #[inline] unsafe fn downcast_ref_unchecked(&self) -> &T { mem::transmute(mem::transmute::<&HeaderFormat, raw::TraitObject>(self).data) } #[inline] unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { mem::transmute(mem::transmute::<&mut HeaderFormat, raw::TraitObject>(self).data) } #[inline] unsafe fn downcast_unchecked(self: Box) -> Box { mem::transmute(mem::transmute::, raw::TraitObject>(self).data) } } impl Clone for Box { #[inline] fn clone(&self) -> Box { self.clone_box() } } #[inline] fn header_name() -> &'static str { let name = ::header_name(); name } /// A map of header fields on requests and responses. #[derive(Clone)] pub struct Headers { data: HashMap> } impl Headers { /// Creates a new, empty headers map. pub fn new() -> Headers { Headers { data: HashMap::new() } } #[doc(hidden)] pub fn from_raw(rdr: &mut R) -> HttpResult { let mut headers = Headers::new(); loop { match try!(http::read_header(rdr)) { Some((name, value)) => { debug!("raw header: {:?}={:?}", name, &value[]); let name = UniCase(Owned(name)); let mut item = match headers.data.entry(name) { Entry::Vacant(entry) => entry.insert(MuCell::new(Item::raw(vec![]))), Entry::Occupied(entry) => entry.into_mut() }; match &mut item.borrow_mut().raw { &mut Some(ref mut raw) => raw.push(value), // Unreachable _ => {} }; }, None => break, } } Ok(headers) } /// Set a header field to the corresponding value. /// /// The field is determined by the type of the value being set. pub fn set(&mut self, value: H) { self.data.insert(UniCase(Borrowed(header_name::())), MuCell::new(Item::typed(Box::new(value)))); } /// Access the raw value of a header. /// /// Prefer to use the typed getters instead. /// /// Example: /// /// ``` /// # use hyper::header::Headers; /// # let mut headers = Headers::new(); /// let raw_content_type = headers.get_raw("content-type"); /// ``` pub fn get_raw(&self, name: &str) -> Option<&[Vec]> { self.data // FIXME(reem): Find a better way to do this lookup without find_equiv. .get(&UniCase(Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) .and_then(|item| { if let Some(ref raw) = item.borrow().raw { return unsafe { mem::transmute(Some(&raw[])) }; } let worked = item.try_mutate(|item| { let raw = vec![item.typed.as_ref().unwrap().to_string().into_bytes()]; item.raw = Some(raw); }); debug_assert!(worked, "item.try_mutate should return true"); let item = item.borrow(); let raw = item.raw.as_ref().unwrap(); unsafe { mem::transmute(Some(&raw[])) } }) } /// Set the raw value of a header, bypassing any typed headers. /// /// Example: /// /// ``` /// # use hyper::header::Headers; /// # let mut headers = Headers::new(); /// headers.set_raw("content-length", vec![b"5".to_vec()]); /// ``` pub fn set_raw>(&mut self, name: K, value: Vec>) { self.data.insert(UniCase(name.into_cow()), MuCell::new(Item::raw(value))); } /// Get a reference to the header field's value, if it exists. pub fn get(&self) -> Option<&H> { self.get_or_parse::().map(|item| { unsafe { mem::transmute::<&H, &H>(downcast(&*item.borrow())) } }) } /// Get a mutable reference to the header field's value, if it exists. pub fn get_mut(&mut self) -> Option<&mut H> { self.get_or_parse_mut::().map(|item| { unsafe { downcast_mut(item.borrow_mut()) } }) } fn get_or_parse(&self) -> Option<&MuCell> { self.data.get(&UniCase(Borrowed(header_name::()))).and_then(get_or_parse::) } fn get_or_parse_mut(&mut self) -> Option<&mut MuCell> { self.data.get_mut(&UniCase(Borrowed(header_name::()))).and_then(get_or_parse_mut::) } /// Returns a boolean of whether a certain header is in the map. /// /// Example: /// /// ``` /// # use hyper::header::Headers; /// # use hyper::header::ContentType; /// # let mut headers = Headers::new(); /// let has_type = headers.has::(); /// ``` pub fn has(&self) -> bool { self.data.contains_key(&UniCase(Borrowed(header_name::()))) } /// Removes a header from the map, if one existed. /// Returns true if a header has been removed. pub fn remove(&mut self) -> bool { self.data.remove(&UniCase(Borrowed(header_name::()))).is_some() } /// Returns an iterator over the header fields. pub fn iter<'a>(&'a self) -> HeadersItems<'a> { HeadersItems { inner: self.data.iter() } } /// Returns the number of headers in the map. pub fn len(&self) -> usize { self.data.len() } /// Remove all headers from the map. pub fn clear(&mut self) { self.data.clear() } } impl fmt::Display for Headers { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { for header in self.iter() { try!(write!(fmt, "{}\r\n", header)); } Ok(()) } } impl fmt::Debug for Headers { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(fmt.write_str("Headers {{ ")); for header in self.iter() { try!(write!(fmt, "{:?}, ", header)); } try!(fmt.write_str("}}")); Ok(()) } } /// An `Iterator` over the fields in a `Headers` map. pub struct HeadersItems<'a> { inner: Iter<'a, HeaderName, MuCell> } impl<'a> Iterator for HeadersItems<'a> { type Item = HeaderView<'a>; fn next(&mut self) -> Option> { match self.inner.next() { Some((k, v)) => Some(HeaderView(k, v)), None => None } } } /// Returned with the `HeadersItems` iterator. pub struct HeaderView<'a>(&'a HeaderName, &'a MuCell); impl<'a> HeaderView<'a> { /// Check if a HeaderView is a certain Header. #[inline] pub fn is(&self) -> bool { UniCase(header_name::().into_cow()) == *self.0 } /// Get the Header name as a slice. #[inline] pub fn name(&self) -> &'a str { self.0.as_slice() } /// Cast the value to a certain Header type. #[inline] pub fn value(&self) -> Option<&'a H> { get_or_parse::(self.1).map(|item| { unsafe { mem::transmute::<&H, &H>(downcast(&*item.borrow())) } }) } /// Get just the header value as a String. #[inline] pub fn value_string(&self) -> String { (*self.1.borrow()).to_string() } } impl<'a> fmt::Display for HeaderView<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}: {}", self.0, *self.1.borrow()) } } impl<'a> fmt::Debug for HeaderView<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, fmt) } } impl<'a> Extend> for Headers { fn extend>>(&mut self, mut iter: I) { for header in iter { self.data.insert((*header.0).clone(), (*header.1).clone()); } } } impl<'a> FromIterator> for Headers { fn from_iter>>(iter: I) -> Headers { let mut headers = Headers::new(); headers.extend(iter); headers } } #[derive(Clone)] struct Item { raw: Option>>, typed: Option> } impl Item { fn raw(data: Vec>) -> Item { Item { raw: Some(data), typed: None, } } fn typed(ty: Box) -> Item { Item { raw: None, typed: Some(ty), } } } fn get_or_parse(item: &MuCell) -> Option<&MuCell> { match item.borrow().typed { Some(ref typed) if typed.is::() => return Some(item), Some(ref typed) => { warn!("attempted to access {:?} as wrong type", typed); return None; } _ => () } let worked = item.try_mutate(parse::); debug_assert!(worked, "item.try_mutate should return true"); if item.borrow().typed.is_some() { Some(item) } else { None } } fn get_or_parse_mut(item: &mut MuCell) -> Option<&mut MuCell> { let is_correct_type = match item.borrow().typed { Some(ref typed) if typed.is::() => Some(true), Some(ref typed) => { warn!("attempted to access {:?} as wrong type", typed); Some(false) } _ => None }; match is_correct_type { Some(true) => return Some(item), Some(false) => return None, None => () } parse::(item.borrow_mut()); if item.borrow().typed.is_some() { Some(item) } else { None } } fn parse(item: &mut Item) { item.typed = match item.raw { Some(ref raw) => match Header::parse_header(&raw[]) { Some::(h) => Some(box h as Box), None => None }, None => unreachable!() }; } unsafe fn downcast(item: &Item) -> &H { item.typed.as_ref().expect("item.typed must be set").downcast_ref_unchecked() } unsafe fn downcast_mut(item: &mut Item) -> &mut H { item.typed.as_mut().expect("item.typed must be set").downcast_mut_unchecked() } impl fmt::Display for Item { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self.typed { Some(ref h) => h.fmt_header(fmt), None => match self.raw { Some(ref raw) => { for part in raw.iter() { match from_utf8(&part[]) { Ok(s) => try!(fmt.write_str(s)), Err(e) => { error!("raw header value is not utf8. header={:?}, error={:?}", part, e); return Err(fmt::Error); } } } Ok(()) }, None => unreachable!() } } } } impl fmt::Debug for Box { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { (**self).fmt_header(fmt) } } impl fmt::Display for Box { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { (**self).fmt_header(fmt) } } /// A wrapper around any Header with a Show impl that calls fmt_header. /// /// This can be used like so: `format!("{}", HeaderFormatter(&header))` to /// get the representation of a Header which will be written to an /// outgoing TcpStream. pub struct HeaderFormatter<'a, H: HeaderFormat>(pub &'a H); impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt_header(f) } } impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt_header(f) } } #[cfg(test)] mod tests { use std::old_io::MemReader; use std::fmt; use std::borrow::Cow::Borrowed; use std::hash::{SipHasher, hash}; use mime::Mime; use mime::TopLevel::Text; use mime::SubLevel::Plain; use unicase::UniCase; use super::{Headers, Header, HeaderFormat, ContentLength, ContentType, Accept, Host, QualityItem}; use test::Bencher; fn mem(s: &str) -> MemReader { MemReader::new(s.as_bytes().to_vec()) } #[test] fn test_case_insensitive() { let a = UniCase(Borrowed("foobar")); let b = UniCase(Borrowed("FOOBAR")); assert_eq!(a, b); assert_eq!(hash::<_, SipHasher>(&a), hash::<_, SipHasher>(&b)); } #[test] fn test_from_raw() { let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).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_slice()); assert_eq!(content_type, Some(ContentType(Mime(Text, Plain, vec![])))); } #[test] fn test_accept() { let text_plain = QualityItem{item: Mime(Text, Plain, vec![]), quality: 1f32}; 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_slice()); assert_eq!(accept, Some(Accept(vec![text_plain.clone()]))); let accept = Header::parse_header([b"application/vnd.github.v3.full+json; q=0.5, text/plain".to_vec()].as_slice()); assert_eq!(accept, Some(Accept(vec![application_vendor, text_plain]))); } #[derive(Clone, Show)] struct CrazyLength(Option, usize); impl Header for CrazyLength { fn header_name() -> &'static str { "content-length" } fn parse_header(raw: &[Vec]) -> Option { use std::str::from_utf8; use std::str::FromStr; if raw.len() != 1 { return None; } // we JUST checked that raw.len() == 1, so raw[0] WILL exist. match from_utf8(unsafe { &raw[].get_unchecked(0)[] }) { Ok(s) => FromStr::from_str(s), Err(_) => None }.map(|u| CrazyLength(Some(false), u)) } } impl HeaderFormat for CrazyLength { fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let CrazyLength(ref opt, ref value) = *self; write!(fmt, "{:?}, {:?}", opt, value) } } #[test] fn test_different_structs_for_same_header() { let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); let ContentLength(_) = *headers.get::().unwrap(); assert!(headers.get::().is_none()); } #[test] fn test_trailing_whitespace() { let headers = Headers::from_raw(&mut mem("Content-Length: 10 \r\n\r\n")).unwrap(); let ContentLength(_) = *headers.get::().unwrap(); assert!(headers.get::().is_none()); } #[test] fn test_multiple_reads() { let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); let ContentLength(one) = *headers.get::().unwrap(); let ContentLength(two) = *headers.get::().unwrap(); assert_eq!(one, two); } #[test] fn test_different_reads() { let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\nContent-Type: text/plain\r\n\r\n")).unwrap(); let ContentLength(_) = *headers.get::().unwrap(); let ContentType(_) = *headers.get::().unwrap(); } #[test] fn test_get_mutable() { let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\nContent-Type: text/plain\r\n\r\n")).unwrap(); *headers.get_mut::().unwrap() = ContentLength(20); assert_eq!(*headers.get::().unwrap(), ContentLength(20)); } #[test] fn test_headers_show() { let mut headers = Headers::new(); headers.set(ContentLength(15)); headers.set(Host { hostname: "foo.bar".to_string(), port: None }); let s = headers.to_string(); // hashmap's iterators have arbitrary order, so we must sort first let mut pieces = s.split_str("\r\n").collect::>(); pieces.sort(); let s = pieces.into_iter().rev().collect::>().connect("\r\n"); assert_eq!(s, "Host: foo.bar\r\nContent-Length: 15\r\n"); } #[test] fn test_headers_show_raw() { let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); let s = headers.to_string(); assert_eq!(s, "Content-Length: 10\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_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); // Redundant, should not increase count. 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::()); assert_eq!(header.name(), ::header_name()); assert_eq!(header.value(), Some(&ContentLength(11))); assert_eq!(header.value_string(), "11".to_string()); } } #[bench] fn bench_header_get(b: &mut Bencher) { let mut headers = Headers::new(); headers.set(ContentLength(11)); b.iter(|| assert_eq!(headers.get::(), Some(&ContentLength(11)))) } #[bench] fn bench_header_get_miss(b: &mut Bencher) { let headers = Headers::new(); b.iter(|| assert!(headers.get::().is_none())) } #[bench] fn bench_header_set(b: &mut Bencher) { let mut headers = Headers::new(); b.iter(|| headers.set(ContentLength(12))) } #[bench] fn bench_header_has(b: &mut Bencher) { let mut headers = Headers::new(); headers.set(ContentLength(11)); b.iter(|| assert!(headers.has::())) } #[bench] fn bench_header_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::())) } }