feat(lib): switch to non-blocking (asynchronous) IO
BREAKING CHANGE: This breaks a lot of the Client and Server APIs. Check the documentation for how Handlers can be used for asynchronous events.
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| use std::fmt::{self, Display}; | ||||
| use std::str; | ||||
| use unicase::UniCase; | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
|  | ||||
| /// `Access-Control-Allow-Credentials` header, part of | ||||
| /// [CORS](http://www.w3.org/TR/cors/#access-control-allow-headers-response-header) | ||||
| @@ -62,9 +62,7 @@ impl Header for AccessControlAllowCredentials { | ||||
|         } | ||||
|         Err(::Error::Header) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for AccessControlAllowCredentials { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.write_str("true") | ||||
|     } | ||||
| @@ -86,4 +84,4 @@ mod test_access_control_allow_credentials { | ||||
|     test_header!(not_bool,     vec![b"false"], None); | ||||
|     test_header!(only_single,  vec![b"true", b"true"], None); | ||||
|     test_header!(no_gibberish, vec!["\u{645}\u{631}\u{62d}\u{628}\u{627}".as_bytes()], None); | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use std::fmt::{self, Display}; | ||||
|  | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
|  | ||||
| /// The `Access-Control-Allow-Origin` response header, | ||||
| /// part of [CORS](http://www.w3.org/TR/cors/#access-control-allow-origin-response-header) | ||||
| @@ -70,9 +70,7 @@ impl Header for AccessControlAllowOrigin { | ||||
|             _ => AccessControlAllowOrigin::Value(try!(String::from_utf8(value.clone()))) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for AccessControlAllowOrigin { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         match *self { | ||||
|             AccessControlAllowOrigin::Any => f.write_str("*"), | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use std::fmt::{self, Display}; | ||||
| use std::str::{FromStr, from_utf8}; | ||||
| use std::ops::{Deref, DerefMut}; | ||||
| use serialize::base64::{ToBase64, FromBase64, Standard, Config, Newline}; | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
|  | ||||
| /// `Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.2) | ||||
| /// | ||||
| @@ -97,9 +97,7 @@ impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'st | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<S: Scheme + Any> HeaderFormat for Authorization<S> where <S as FromStr>::Err: 'static { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         if let Some(scheme) = <S as Scheme>::scheme() { | ||||
|             try!(write!(f, "{} ", scheme)) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use std::fmt; | ||||
| use std::str::FromStr; | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::Header; | ||||
| use header::parsing::{from_comma_delimited, fmt_comma_delimited}; | ||||
|  | ||||
| /// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2) | ||||
| @@ -62,9 +62,7 @@ impl Header for CacheControl { | ||||
|             Err(::Error::Header) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for CacheControl { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt_comma_delimited(f, &self[..]) | ||||
|     } | ||||
|   | ||||
| @@ -11,7 +11,7 @@ use std::fmt; | ||||
| use unicase::UniCase; | ||||
| use url::percent_encoding; | ||||
|  | ||||
| use header::{Header, HeaderFormat, parsing}; | ||||
| use header::{Header, parsing}; | ||||
| use header::parsing::{parse_extended_value, HTTP_VALUE}; | ||||
| use header::shared::Charset; | ||||
|  | ||||
| @@ -144,9 +144,7 @@ impl Header for ContentDisposition { | ||||
|             Ok(cd) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for ContentDisposition { | ||||
|     #[inline] | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt::Display::fmt(&self, f) | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use std::fmt; | ||||
|  | ||||
| use header::{HeaderFormat, Header, parsing}; | ||||
| use header::{Header, parsing}; | ||||
|  | ||||
| /// `Content-Length` header, defined in | ||||
| /// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2) | ||||
| @@ -55,9 +55,7 @@ impl Header for ContentLength { | ||||
|             .unwrap_or(Err(::Error::Header)) | ||||
|             .map(ContentLength) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for ContentLength { | ||||
|     #[inline] | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt::Display::fmt(&self.0, f) | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| use header::{Header, HeaderFormat, CookiePair, CookieJar}; | ||||
| use header::{Header, CookiePair, CookieJar}; | ||||
| use std::fmt::{self, Display}; | ||||
| use std::str::from_utf8; | ||||
|  | ||||
| @@ -61,9 +61,7 @@ impl Header for Cookie { | ||||
|             Err(::Error::Header) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for Cookie { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let cookies = &self.0; | ||||
|         for (i, cookie) in cookies.iter().enumerate() { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use std::str; | ||||
|  | ||||
| use unicase::UniCase; | ||||
|  | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
|  | ||||
| /// The `Expect` header. | ||||
| /// | ||||
| @@ -53,9 +53,7 @@ impl Header for Expect { | ||||
|             Err(::Error::Header) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for Expect { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.write_str("100-continue") | ||||
|     } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
| use std::fmt; | ||||
| use header::parsing::from_one_raw_str; | ||||
|  | ||||
| @@ -52,9 +52,7 @@ impl Header for Host { | ||||
|             // https://github.com/servo/rust-url/issues/42 | ||||
|             let idx = { | ||||
|                 let slice = &s[..]; | ||||
|                 let mut chars = slice.chars(); | ||||
|                 chars.next(); | ||||
|                 if chars.next().unwrap() == '[' { | ||||
|                 if slice.starts_with('[') { | ||||
|                     match slice.rfind(']') { | ||||
|                         Some(idx) => { | ||||
|                             if slice.len() > idx + 2 { | ||||
| @@ -86,9 +84,7 @@ impl Header for Host { | ||||
|             }) | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for Host { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         match self.port { | ||||
|             None | Some(80) | Some(443) => f.write_str(&self.hostname[..]), | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use std::fmt::{self, Display}; | ||||
| use header::{self, Header, HeaderFormat, EntityTag, HttpDate}; | ||||
| use header::{self, Header, EntityTag, HttpDate}; | ||||
|  | ||||
| /// `If-Range` header, defined in [RFC7233](http://tools.ietf.org/html/rfc7233#section-3.2) | ||||
| /// | ||||
| @@ -59,18 +59,16 @@ impl Header for IfRange { | ||||
|     } | ||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<IfRange> { | ||||
|         let etag: ::Result<EntityTag> = header::parsing::from_one_raw_str(raw); | ||||
|         if etag.is_ok() { | ||||
|             return Ok(IfRange::EntityTag(etag.unwrap())); | ||||
|         if let Ok(etag) = etag { | ||||
|             return Ok(IfRange::EntityTag(etag)); | ||||
|         } | ||||
|         let date: ::Result<HttpDate> = header::parsing::from_one_raw_str(raw); | ||||
|         if date.is_ok() { | ||||
|             return Ok(IfRange::Date(date.unwrap())); | ||||
|         if let Ok(date) = date { | ||||
|             return Ok(IfRange::Date(date)); | ||||
|         } | ||||
|         Err(::Error::Header) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for IfRange { | ||||
|     fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|         match *self { | ||||
|             IfRange::EntityTag(ref x) => Display::fmt(x, f), | ||||
|   | ||||
| @@ -66,7 +66,7 @@ macro_rules! bench_header( | ||||
|             use test::Bencher; | ||||
|             use super::*; | ||||
|  | ||||
|             use header::{Header, HeaderFormatter}; | ||||
|             use header::{Header}; | ||||
|  | ||||
|             #[bench] | ||||
|             fn bench_parse(b: &mut Bencher) { | ||||
| @@ -79,7 +79,7 @@ macro_rules! bench_header( | ||||
|             #[bench] | ||||
|             fn bench_format(b: &mut Bencher) { | ||||
|                 let val: $ty = Header::parse_header(&$value[..]).unwrap(); | ||||
|                 let fmt = HeaderFormatter(&val); | ||||
|                 let fmt = ::header::HeaderFormatter(&val); | ||||
|                 b.iter(|| { | ||||
|                     format!("{}", fmt); | ||||
|                 }); | ||||
| @@ -222,15 +222,13 @@ macro_rules! header { | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id) | ||||
|             } | ||||
|         } | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 $crate::header::parsing::fmt_comma_delimited(f, &self.0[..]) | ||||
|             } | ||||
|         } | ||||
|         impl ::std::fmt::Display for $id { | ||||
|             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 use $crate::header::HeaderFormat; | ||||
|                 use $crate::header::Header; | ||||
|                 self.fmt_header(f) | ||||
|             } | ||||
|         } | ||||
| @@ -250,15 +248,13 @@ macro_rules! header { | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id) | ||||
|             } | ||||
|         } | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 $crate::header::parsing::fmt_comma_delimited(f, &self.0[..]) | ||||
|             } | ||||
|         } | ||||
|         impl ::std::fmt::Display for $id { | ||||
|             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 use $crate::header::HeaderFormat; | ||||
|                 use $crate::header::Header; | ||||
|                 self.fmt_header(f) | ||||
|             } | ||||
|         } | ||||
| @@ -277,8 +273,6 @@ macro_rules! header { | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> { | ||||
|                 $crate::header::parsing::from_one_raw_str(raw).map($id) | ||||
|             } | ||||
|         } | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 ::std::fmt::Display::fmt(&**self, f) | ||||
|             } | ||||
| @@ -313,8 +307,6 @@ macro_rules! header { | ||||
|                 } | ||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id::Items) | ||||
|             } | ||||
|         } | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 match *self { | ||||
|                     $id::Any => f.write_str("*"), | ||||
| @@ -325,7 +317,7 @@ macro_rules! header { | ||||
|         } | ||||
|         impl ::std::fmt::Display for $id { | ||||
|             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 use $crate::header::HeaderFormat; | ||||
|                 use $crate::header::Header; | ||||
|                 self.fmt_header(f) | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use std::fmt; | ||||
| use std::ascii::AsciiExt; | ||||
|  | ||||
| use header::{Header, HeaderFormat, parsing}; | ||||
| use header::{Header, parsing}; | ||||
|  | ||||
| /// The `Pragma` header defined by HTTP/1.0. | ||||
| /// | ||||
| @@ -52,9 +52,7 @@ impl Header for Pragma { | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for Pragma { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.write_str(match *self { | ||||
|             Pragma::NoCache => "no-cache", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| use std::fmt; | ||||
| use std::str::FromStr; | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
| use header::parsing::{from_comma_delimited, fmt_comma_delimited}; | ||||
|  | ||||
| /// `Prefer` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240) | ||||
| @@ -64,9 +64,7 @@ impl Header for Prefer { | ||||
|             Err(::Error::Header) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for Prefer { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         fmt_comma_delimited(f, &self[..]) | ||||
|     } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use std::fmt; | ||||
| use header::{Header, HeaderFormat, Preference}; | ||||
| use header::{Header, Preference}; | ||||
| use header::parsing::{from_comma_delimited, fmt_comma_delimited}; | ||||
|  | ||||
| /// `Preference-Applied` header, defined in [RFC7240](http://tools.ietf.org/html/rfc7240) | ||||
| @@ -61,9 +61,7 @@ impl Header for PreferenceApplied { | ||||
|             Err(::Error::Header) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for PreferenceApplied { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let preferences: Vec<_> = self.0.iter().map(|pref| match pref { | ||||
|             // The spec ignores parameters in `Preferences-Applied` | ||||
| @@ -80,7 +78,7 @@ impl HeaderFormat for PreferenceApplied { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use header::{HeaderFormat, Preference}; | ||||
|     use header::{Header, Preference}; | ||||
|     use super::*; | ||||
|  | ||||
|     #[test] | ||||
| @@ -90,7 +88,7 @@ mod tests { | ||||
|                 "foo".to_owned(), | ||||
|                 "bar".to_owned(), | ||||
|                 vec![("bar".to_owned(), "foo".to_owned()), ("buz".to_owned(), "".to_owned())] | ||||
|             )]) as &(HeaderFormat + Send + Sync)), | ||||
|             )]) as &(Header + Send + Sync)), | ||||
|             "foo=bar".to_owned() | ||||
|         ); | ||||
|     } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| use std::fmt::{self, Display}; | ||||
| use std::str::FromStr; | ||||
|  | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::Header; | ||||
| use header::parsing::{from_one_raw_str, from_comma_delimited}; | ||||
|  | ||||
| /// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1) | ||||
| @@ -182,9 +182,6 @@ impl Header for Range { | ||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Range> { | ||||
|         from_one_raw_str(raw) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for Range { | ||||
|  | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         Display::fmt(self, f) | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| use header::{Header, HeaderFormat, CookiePair, CookieJar}; | ||||
| use header::{Header, CookiePair, CookieJar}; | ||||
| use std::fmt::{self, Display}; | ||||
| use std::str::from_utf8; | ||||
|  | ||||
| @@ -104,10 +104,6 @@ impl Header for SetCookie { | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for SetCookie { | ||||
|  | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         for (i, cookie) in self.0.iter().enumerate() { | ||||
|             if i != 0 { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use std::str::{self, FromStr}; | ||||
|  | ||||
| use unicase::UniCase; | ||||
|  | ||||
| use header::{Header, HeaderFormat, parsing}; | ||||
| use header::{Header, parsing}; | ||||
|  | ||||
| /// `StrictTransportSecurity` header, defined in [RFC6797](https://tools.ietf.org/html/rfc6797) | ||||
| /// | ||||
| @@ -127,9 +127,7 @@ impl Header for StrictTransportSecurity { | ||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<StrictTransportSecurity> { | ||||
|         parsing::from_one_raw_str(raw) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat for StrictTransportSecurity { | ||||
|     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         if self.include_subdomains { | ||||
|             write!(f, "max-age={}; includeSubdomains", self.max_age) | ||||
|   | ||||
| @@ -49,5 +49,12 @@ header! { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl TransferEncoding { | ||||
|     /// Constructor for the most common Transfer-Encoding, `chunked`. | ||||
|     pub fn chunked() -> TransferEncoding { | ||||
|         TransferEncoding(vec![Encoding::Chunked]) | ||||
|     } | ||||
| } | ||||
|  | ||||
| bench_header!(normal, TransferEncoding, { vec![b"chunked, gzip".to_vec()] }); | ||||
| bench_header!(ext, TransferEncoding, { vec![b"ext".to_vec()] }); | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| use std::any::{Any, TypeId}; | ||||
| use std::cell::UnsafeCell; | ||||
| use std::collections::HashMap; | ||||
| use std::fmt; | ||||
| use std::mem; | ||||
| use std::ops::Deref; | ||||
|  | ||||
| @@ -53,7 +52,7 @@ enum PtrMap<T> { | ||||
|     Many(HashMap<TypeId, T>) | ||||
| } | ||||
|  | ||||
| impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> { | ||||
| impl<V: ?Sized + Any + 'static> PtrMapCell<V> { | ||||
|     #[inline] | ||||
|     pub fn new() -> PtrMapCell<V> { | ||||
|         PtrMapCell(UnsafeCell::new(PtrMap::Empty)) | ||||
| @@ -114,12 +113,12 @@ impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> { | ||||
|         let map = &*self.0.get(); | ||||
|         match *map { | ||||
|             PtrMap::One(_, ref one) => one, | ||||
|             _ => panic!("not PtrMap::One value, {:?}", *map) | ||||
|             _ => panic!("not PtrMap::One value") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<V: ?Sized + fmt::Debug + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone { | ||||
| impl<V: ?Sized + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone { | ||||
|     #[inline] | ||||
|     fn clone(&self) -> PtrMapCell<V> { | ||||
|         let cell = PtrMapCell::new(); | ||||
|   | ||||
| @@ -4,13 +4,13 @@ use std::fmt; | ||||
| use std::str::from_utf8; | ||||
|  | ||||
| use super::cell::{OptCell, PtrMapCell}; | ||||
| use header::{Header, HeaderFormat}; | ||||
| use header::{Header}; | ||||
|  | ||||
|  | ||||
| #[derive(Clone)] | ||||
| pub struct Item { | ||||
|     raw: OptCell<Vec<Vec<u8>>>, | ||||
|     typed: PtrMapCell<HeaderFormat + Send + Sync> | ||||
|     typed: PtrMapCell<Header + Send + Sync> | ||||
| } | ||||
|  | ||||
| impl Item { | ||||
| @@ -23,7 +23,7 @@ impl Item { | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     pub fn new_typed(ty: Box<HeaderFormat + Send + Sync>) -> Item { | ||||
|     pub fn new_typed(ty: Box<Header + Send + Sync>) -> Item { | ||||
|         let map = PtrMapCell::new(); | ||||
|         unsafe { map.insert((*ty).get_type(), ty); } | ||||
|         Item { | ||||
| @@ -52,7 +52,7 @@ impl Item { | ||||
|         &raw[..] | ||||
|     } | ||||
|  | ||||
|     pub fn typed<H: Header + HeaderFormat + Any>(&self) -> Option<&H> { | ||||
|     pub fn typed<H: Header + Any>(&self) -> Option<&H> { | ||||
|         let tid = TypeId::of::<H>(); | ||||
|         match self.typed.get(tid) { | ||||
|             Some(val) => Some(val), | ||||
| @@ -68,7 +68,7 @@ impl Item { | ||||
|         }.map(|typed| unsafe { typed.downcast_ref_unchecked() }) | ||||
|     } | ||||
|  | ||||
|     pub fn typed_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> { | ||||
|     pub fn typed_mut<H: Header>(&mut self) -> Option<&mut H> { | ||||
|         let tid = TypeId::of::<H>(); | ||||
|         if self.typed.get_mut(tid).is_none() { | ||||
|             match parse::<H>(self.raw.as_ref().expect("item.raw must exist")) { | ||||
| @@ -83,11 +83,11 @@ impl Item { | ||||
| } | ||||
|  | ||||
| #[inline] | ||||
| fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) -> | ||||
|         ::Result<Box<HeaderFormat + Send + Sync>> { | ||||
| fn parse<H: Header>(raw: &Vec<Vec<u8>>) -> | ||||
|         ::Result<Box<Header + Send + Sync>> { | ||||
|     Header::parse_header(&raw[..]).map(|h: H| { | ||||
|         // FIXME: Use Type ascription | ||||
|         let h: Box<HeaderFormat + Send + Sync> = Box::new(h); | ||||
|         let h: Box<Header + Send + Sync> = Box::new(h); | ||||
|         h | ||||
|     }) | ||||
| } | ||||
|   | ||||
| @@ -31,18 +31,17 @@ | ||||
| //! } | ||||
| //! ``` | ||||
| //! | ||||
| //! This works well for simple "string" headers. But the header system | ||||
| //! actually involves 2 parts: parsing, and formatting. If you need to | ||||
| //! customize either part, you can do so. | ||||
| //! This works well for simple "string" headers.  If you need more control, | ||||
| //! you can implement the trait directly. | ||||
| //! | ||||
| //! ## `Header` and `HeaderFormat` | ||||
| //! ## Implementing the `Header` trait | ||||
| //! | ||||
| //! Consider a Do Not Track header. It can be true or false, but it represents | ||||
| //! that via the numerals `1` and `0`. | ||||
| //! | ||||
| //! ``` | ||||
| //! use std::fmt; | ||||
| //! use hyper::header::{Header, HeaderFormat}; | ||||
| //! use hyper::header::Header; | ||||
| //! | ||||
| //! #[derive(Debug, Clone, Copy)] | ||||
| //! struct Dnt(bool); | ||||
| @@ -66,9 +65,7 @@ | ||||
| //!         } | ||||
| //!         Err(hyper::Error::Header) | ||||
| //!     } | ||||
| //! } | ||||
| //! | ||||
| //! impl HeaderFormat for Dnt { | ||||
| //!     fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
| //!         if self.0 { | ||||
| //!             f.write_str("1") | ||||
| @@ -113,11 +110,11 @@ type HeaderName = UniCase<CowStr>; | ||||
| /// | ||||
| /// This trait represents the construction and identification of headers, | ||||
| /// and contains trait-object unsafe methods. | ||||
| pub trait Header: Clone + Any + Send + Sync { | ||||
| pub trait Header: HeaderClone + Any + Typeable + 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; | ||||
|     fn header_name() -> &'static str where Self: Sized; | ||||
|     /// Parse a header from a raw stream of bytes. | ||||
|     /// | ||||
|     /// It's possible that a request can include a header field more than once, | ||||
| @@ -125,35 +122,27 @@ pub trait Header: Clone + Any + Send + Sync { | ||||
|     /// 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<u8>]) -> ::Result<Self>; | ||||
|  | ||||
| } | ||||
|  | ||||
| /// 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: fmt::Debug + HeaderClone + Any + Typeable + Send + Sync { | ||||
|     fn parse_header(raw: &[Vec<u8>]) -> ::Result<Self> where Self: Sized; | ||||
|     /// 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, f: &mut fmt::Formatter) -> fmt::Result; | ||||
|  | ||||
| } | ||||
|  | ||||
| #[doc(hidden)] | ||||
| pub trait HeaderClone { | ||||
|     fn clone_box(&self) -> Box<HeaderFormat + Send + Sync>; | ||||
|     fn clone_box(&self) -> Box<Header + Send + Sync>; | ||||
| } | ||||
|  | ||||
| impl<T: HeaderFormat + Clone> HeaderClone for T { | ||||
| impl<T: Header + Clone> HeaderClone for T { | ||||
|     #[inline] | ||||
|     fn clone_box(&self) -> Box<HeaderFormat + Send + Sync> { | ||||
|     fn clone_box(&self) -> Box<Header + Send + Sync> { | ||||
|         Box::new(self.clone()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl HeaderFormat + Send + Sync { | ||||
| impl Header + Send + Sync { | ||||
|     #[inline] | ||||
|     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { | ||||
|         mem::transmute(traitobject::data(self)) | ||||
| @@ -165,9 +154,9 @@ impl HeaderFormat + Send + Sync { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Clone for Box<HeaderFormat + Send + Sync> { | ||||
| impl Clone for Box<Header + Send + Sync> { | ||||
|     #[inline] | ||||
|     fn clone(&self) -> Box<HeaderFormat + Send + Sync> { | ||||
|     fn clone(&self) -> Box<Header + Send + Sync> { | ||||
|         self.clone_box() | ||||
|     } | ||||
| } | ||||
| @@ -183,6 +172,12 @@ pub struct Headers { | ||||
|     data: HashMap<HeaderName, Item> | ||||
| } | ||||
|  | ||||
| impl Default for Headers { | ||||
|     fn default() -> Headers { | ||||
|         Headers::new() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Headers { | ||||
|  | ||||
|     /// Creates a new, empty headers map. | ||||
| @@ -212,8 +207,8 @@ impl Headers { | ||||
|     /// Set a header field to the corresponding value. | ||||
|     /// | ||||
|     /// The field is determined by the type of the value being set. | ||||
|     pub fn set<H: Header + HeaderFormat>(&mut self, value: H) { | ||||
|         trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), value); | ||||
|     pub fn set<H: Header>(&mut self, value: H) { | ||||
|         trace!("Headers.set( {:?}, {:?} )", header_name::<H>(), HeaderFormatter(&value)); | ||||
|         self.data.insert(UniCase(CowStr(Cow::Borrowed(header_name::<H>()))), | ||||
|                          Item::new_typed(Box::new(value))); | ||||
|     } | ||||
| @@ -259,13 +254,13 @@ impl Headers { | ||||
|     } | ||||
|  | ||||
|     /// Get a reference to the header field's value, if it exists. | ||||
|     pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> { | ||||
|     pub fn get<H: Header>(&self) -> Option<&H> { | ||||
|         self.data.get(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))) | ||||
|         .and_then(Item::typed::<H>) | ||||
|     } | ||||
|  | ||||
|     /// Get a mutable reference to the header field's value, if it exists. | ||||
|     pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> { | ||||
|     pub fn get_mut<H: Header>(&mut self) -> Option<&mut H> { | ||||
|         self.data.get_mut(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))) | ||||
|         .and_then(Item::typed_mut::<H>) | ||||
|     } | ||||
| @@ -280,13 +275,13 @@ impl Headers { | ||||
|     /// # let mut headers = Headers::new(); | ||||
|     /// let has_type = headers.has::<ContentType>(); | ||||
|     /// ``` | ||||
|     pub fn has<H: Header + HeaderFormat>(&self) -> bool { | ||||
|     pub fn has<H: Header>(&self) -> bool { | ||||
|         self.data.contains_key(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))) | ||||
|     } | ||||
|  | ||||
|     /// Removes a header from the map, if one existed. | ||||
|     /// Returns true if a header has been removed. | ||||
|     pub fn remove<H: Header + HeaderFormat>(&mut self) -> bool { | ||||
|     pub fn remove<H: Header>(&mut self) -> bool { | ||||
|         trace!("Headers.remove( {:?} )", header_name::<H>()); | ||||
|         self.data.remove(&UniCase(CowStr(Cow::Borrowed(header_name::<H>())))).is_some() | ||||
|     } | ||||
| @@ -380,6 +375,7 @@ impl Deserialize for Headers { | ||||
| } | ||||
|  | ||||
| /// An `Iterator` over the fields in a `Headers` map. | ||||
| #[allow(missing_debug_implementations)] | ||||
| pub struct HeadersItems<'a> { | ||||
|     inner: Iter<'a, HeaderName, Item> | ||||
| } | ||||
| @@ -410,7 +406,7 @@ impl<'a> HeaderView<'a> { | ||||
|  | ||||
|     /// Cast the value to a certain Header type. | ||||
|     #[inline] | ||||
|     pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> { | ||||
|     pub fn value<H: Header>(&self) -> Option<&'a H> { | ||||
|         self.1.typed::<H>() | ||||
|     } | ||||
|  | ||||
| @@ -449,7 +445,7 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) { | ||||
| impl<'a> fmt::Display for &'a (Header + Send + Sync) { | ||||
|     #[inline] | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         (**self).fmt_header(f) | ||||
| @@ -461,16 +457,16 @@ impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) { | ||||
| /// 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); | ||||
| pub struct HeaderFormatter<'a, H: Header>(pub &'a H); | ||||
|  | ||||
| impl<'a, H: HeaderFormat> fmt::Display for HeaderFormatter<'a, H> { | ||||
| impl<'a, H: Header> fmt::Display for HeaderFormatter<'a, H> { | ||||
|     #[inline] | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.0.fmt_header(f) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a, H: HeaderFormat> fmt::Debug for HeaderFormatter<'a, H> { | ||||
| impl<'a, H: Header> fmt::Debug for HeaderFormatter<'a, H> { | ||||
|     #[inline] | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         self.0.fmt_header(f) | ||||
| @@ -519,7 +515,7 @@ mod tests { | ||||
|     use mime::Mime; | ||||
|     use mime::TopLevel::Text; | ||||
|     use mime::SubLevel::Plain; | ||||
|     use super::{Headers, Header, HeaderFormat, ContentLength, ContentType, | ||||
|     use super::{Headers, Header, ContentLength, ContentType, | ||||
|                 Accept, Host, qitem}; | ||||
|     use httparse; | ||||
|  | ||||
| @@ -597,9 +593,7 @@ mod tests { | ||||
|                 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) | ||||
|   | ||||
| @@ -137,6 +137,12 @@ define_encode_set! { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for HTTP_VALUE { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.pad("HTTP_VALUE") | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Display for ExtendedValue { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let encoded_value = | ||||
|   | ||||
		Reference in New Issue
	
	Block a user