feat(headers): adds re-parsing ability when getting typed headers
BREAKING CHANGE: added requirement that all HeaderFormat implementations must also be fmt::Debug. This likely as easy as slapping #[derive(Debug)] on to any custom headers.
This commit is contained in:
		| @@ -19,5 +19,4 @@ openssl = "*" | |||||||
| rustc-serialize = "*" | rustc-serialize = "*" | ||||||
| time = "*" | time = "*" | ||||||
| unicase = "*" | unicase = "*" | ||||||
| unsafe-any = "*" |  | ||||||
| url = "*" | url = "*" | ||||||
|   | |||||||
| @@ -50,7 +50,7 @@ impl Write for MockStream { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone, Debug)] | ||||||
| struct Foo; | struct Foo; | ||||||
|  |  | ||||||
| impl hyper::header::Header for Foo { | impl hyper::header::Header for Foo { | ||||||
|   | |||||||
| @@ -1,41 +0,0 @@ | |||||||
| use std::cell::UnsafeCell; |  | ||||||
| use std::ops::Deref; |  | ||||||
|  |  | ||||||
| pub struct OptCell<T>(UnsafeCell<Option<T>>); |  | ||||||
|  |  | ||||||
| impl<T> OptCell<T> { |  | ||||||
|     #[inline] |  | ||||||
|     pub fn new(val: Option<T>) -> OptCell<T> { |  | ||||||
|         OptCell(UnsafeCell::new(val)) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     pub fn set(&self, val: T) { |  | ||||||
|         unsafe { |  | ||||||
|             let opt = self.0.get(); |  | ||||||
|             debug_assert!((*opt).is_none()); |  | ||||||
|             *opt = Some(val) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     pub unsafe fn get_mut(&mut self) -> &mut T { |  | ||||||
|         let opt = &mut *self.0.get(); |  | ||||||
|         opt.as_mut().unwrap() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<T> Deref for OptCell<T> { |  | ||||||
|     type Target = Option<T>; |  | ||||||
|     #[inline] |  | ||||||
|     fn deref<'a>(&'a self) -> &'a Option<T> { |  | ||||||
|         unsafe { &*self.0.get() } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<T: Clone> Clone for OptCell<T> { |  | ||||||
|     #[inline] |  | ||||||
|     fn clone(&self) -> OptCell<T> { |  | ||||||
|         OptCell::new((**self).clone()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -54,7 +54,7 @@ impl<S: Scheme + 'static> HeaderFormat for Authorization<S> where <S as FromStr> | |||||||
| } | } | ||||||
|  |  | ||||||
| /// An Authorization scheme to be used in the header. | /// An Authorization scheme to be used in the header. | ||||||
| pub trait Scheme: FromStr + Clone + Send + Sync { | pub trait Scheme: FromStr + fmt::Debug + Clone + Send + Sync { | ||||||
|     /// An optional Scheme name. |     /// An optional Scheme name. | ||||||
|     /// |     /// | ||||||
|     /// For example, `Basic asdf` has the name `Basic`. The Option<Self> is |     /// For example, `Basic asdf` has the name `Basic`. The Option<Self> is | ||||||
|   | |||||||
							
								
								
									
										131
									
								
								src/header/internals/cell.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/header/internals/cell.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | |||||||
|  | use std::any::{Any, TypeId}; | ||||||
|  | use std::cell::UnsafeCell; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use std::fmt; | ||||||
|  | use std::mem; | ||||||
|  | use std::ops::Deref; | ||||||
|  |  | ||||||
|  | pub struct OptCell<T>(UnsafeCell<Option<T>>); | ||||||
|  |  | ||||||
|  | impl<T> OptCell<T> { | ||||||
|  |     #[inline] | ||||||
|  |     pub fn new(val: Option<T>) -> OptCell<T> { | ||||||
|  |         OptCell(UnsafeCell::new(val)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub fn set(&self, val: T) { | ||||||
|  |         unsafe { | ||||||
|  |             let opt = self.0.get(); | ||||||
|  |             debug_assert!((*opt).is_none()); | ||||||
|  |             *opt = Some(val) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub unsafe fn get_mut(&mut self) -> &mut T { | ||||||
|  |         let opt = &mut *self.0.get(); | ||||||
|  |         opt.as_mut().unwrap() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T> Deref for OptCell<T> { | ||||||
|  |     type Target = Option<T>; | ||||||
|  |     #[inline] | ||||||
|  |     fn deref<'a>(&'a self) -> &'a Option<T> { | ||||||
|  |         unsafe { &*self.0.get() } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T: Clone> Clone for OptCell<T> { | ||||||
|  |     #[inline] | ||||||
|  |     fn clone(&self) -> OptCell<T> { | ||||||
|  |         OptCell::new((**self).clone()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct PtrMapCell<V: ?Sized>(UnsafeCell<PtrMap<Box<V>>>); | ||||||
|  |  | ||||||
|  | #[derive(Clone, Debug)] | ||||||
|  | enum PtrMap<T> { | ||||||
|  |     Empty, | ||||||
|  |     One(TypeId, T), | ||||||
|  |     Many(HashMap<TypeId, T>) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<V: ?Sized + fmt::Debug + Any + 'static> PtrMapCell<V> { | ||||||
|  |     #[inline] | ||||||
|  |     pub fn new() -> PtrMapCell<V> { | ||||||
|  |         PtrMapCell(UnsafeCell::new(PtrMap::Empty)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub fn get(&self, key: TypeId) -> Option<&V> { | ||||||
|  |         let map = unsafe { &*self.0.get() }; | ||||||
|  |         match *map { | ||||||
|  |             PtrMap::Empty => None, | ||||||
|  |             PtrMap::One(id, ref v) => if id == key { | ||||||
|  |                 Some(v) | ||||||
|  |             } else { | ||||||
|  |                 None | ||||||
|  |             }, | ||||||
|  |             PtrMap::Many(ref hm) => hm.get(&key) | ||||||
|  |         }.map(|val| &**val) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub fn get_mut(&mut self, key: TypeId) -> Option<&mut V> { | ||||||
|  |         let mut map = unsafe { &mut *self.0.get() }; | ||||||
|  |         match *map { | ||||||
|  |             PtrMap::Empty => None, | ||||||
|  |             PtrMap::One(id, ref mut v) => if id == key { | ||||||
|  |                 Some(v) | ||||||
|  |             } else { | ||||||
|  |                 None | ||||||
|  |             }, | ||||||
|  |             PtrMap::Many(ref mut hm) => hm.get_mut(&key) | ||||||
|  |         }.map(|val| &mut **val) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub unsafe fn insert(&self, key: TypeId, val: Box<V>) { | ||||||
|  |         let mut map = &mut *self.0.get(); | ||||||
|  |         match *map { | ||||||
|  |             PtrMap::Empty => *map = PtrMap::One(key, val), | ||||||
|  |             PtrMap::One(..) => { | ||||||
|  |                 let one = mem::replace(map, PtrMap::Empty); | ||||||
|  |                 match one { | ||||||
|  |                     PtrMap::One(id, one) => { | ||||||
|  |                         debug_assert!(id != key); | ||||||
|  |                         let mut hm = HashMap::with_capacity(2); | ||||||
|  |                         hm.insert(id, one); | ||||||
|  |                         hm.insert(key, val); | ||||||
|  |                         mem::replace(map, PtrMap::Many(hm)); | ||||||
|  |                     }, | ||||||
|  |                     _ => unreachable!() | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             PtrMap::Many(ref mut hm) => { hm.insert(key, val); } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub unsafe fn one(&self) -> &V { | ||||||
|  |         let map = &*self.0.get(); | ||||||
|  |         match *map { | ||||||
|  |             PtrMap::One(_, ref one) => one, | ||||||
|  |             _ => panic!("not PtrMap::One value, {:?}", *map) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<V: ?Sized + fmt::Debug + Any + 'static> Clone for PtrMapCell<V> where Box<V>: Clone { | ||||||
|  |     #[inline] | ||||||
|  |     fn clone(&self) -> PtrMapCell<V> { | ||||||
|  |         let cell = PtrMapCell::new(); | ||||||
|  |         unsafe { | ||||||
|  |             *cell.0.get() = (&*self.0.get()).clone() | ||||||
|  |         } | ||||||
|  |         cell | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										107
									
								
								src/header/internals/item.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/header/internals/item.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | |||||||
|  | use std::any::TypeId; | ||||||
|  | use std::fmt; | ||||||
|  | use std::str::from_utf8; | ||||||
|  |  | ||||||
|  | use super::cell::{OptCell, PtrMapCell}; | ||||||
|  | use header::{Header, HeaderFormat}; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #[derive(Clone)] | ||||||
|  | pub struct Item { | ||||||
|  |     raw: OptCell<Vec<Vec<u8>>>, | ||||||
|  |     typed: PtrMapCell<HeaderFormat + Send + Sync> | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Item { | ||||||
|  |     #[inline] | ||||||
|  |     pub fn new_raw(data: Vec<Vec<u8>>) -> Item { | ||||||
|  |         Item { | ||||||
|  |             raw: OptCell::new(Some(data)), | ||||||
|  |             typed: PtrMapCell::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub fn new_typed(ty: Box<HeaderFormat + Send + Sync>) -> Item { | ||||||
|  |         let map = PtrMapCell::new(); | ||||||
|  |         unsafe { map.insert((&*ty).get_type_id(), ty); } | ||||||
|  |         Item { | ||||||
|  |             raw: OptCell::new(None), | ||||||
|  |             typed: map, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     #[inline] | ||||||
|  |     pub fn mut_raw(&mut self) -> &mut Vec<Vec<u8>> { | ||||||
|  |         self.typed = PtrMapCell::new(); | ||||||
|  |         unsafe { | ||||||
|  |             self.raw.get_mut() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn raw(&self) -> &[Vec<u8>] { | ||||||
|  |         if let Some(ref raw) = *self.raw { | ||||||
|  |             return &raw[..]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let raw = vec![unsafe { self.typed.one() }.to_string().into_bytes()]; | ||||||
|  |         self.raw.set(raw); | ||||||
|  |  | ||||||
|  |         let raw = self.raw.as_ref().unwrap(); | ||||||
|  |         &raw[..] | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn typed<H: Header + HeaderFormat>(&self) -> Option<&H> { | ||||||
|  |         let tid = TypeId::of::<H>(); | ||||||
|  |         match self.typed.get(tid) { | ||||||
|  |             Some(val) => Some(val), | ||||||
|  |             None => { | ||||||
|  |                 match parse::<H>(self.raw.as_ref().expect("item.raw must exist")) { | ||||||
|  |                     Some(typed) => { | ||||||
|  |                         unsafe { self.typed.insert(tid, typed); } | ||||||
|  |                         self.typed.get(tid) | ||||||
|  |                     }, | ||||||
|  |                     None => None | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }.map(|typed| unsafe { typed.downcast_ref_unchecked() }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn typed_mut<H: Header + HeaderFormat>(&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")) { | ||||||
|  |                 Some(typed) => { | ||||||
|  |                     unsafe { self.typed.insert(tid, typed); } | ||||||
|  |                 }, | ||||||
|  |                 None => () | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         self.typed.get_mut(tid).map(|typed| unsafe { typed.downcast_mut_unchecked() }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[inline] | ||||||
|  | fn parse<H: Header + HeaderFormat>(raw: &Vec<Vec<u8>>) -> Option<Box<HeaderFormat + Send + Sync>> { | ||||||
|  |     Header::parse_header(&raw[..]).map(|h: H| box h as Box<HeaderFormat + Send + Sync>) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl fmt::Display for Item { | ||||||
|  |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|  |         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 => fmt::Display::fmt(&unsafe { self.typed.one() }, fmt) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								src/header/internals/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/header/internals/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | pub use self::item::Item; | ||||||
|  |  | ||||||
|  | mod cell; | ||||||
|  | mod item; | ||||||
| @@ -4,29 +4,27 @@ | |||||||
| //! why we're using Rust in the first place. To set or get any header, an object | //! 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 | //! must implement the `Header` trait from this module. Several common headers | ||||||
| //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | //! are already provided, such as `Host`, `ContentType`, `UserAgent`, and others. | ||||||
| use std::any::{Any, TypeId}; | use std::any::Any; | ||||||
| use std::borrow::Cow::{Borrowed, Owned}; | use std::borrow::Cow::{Borrowed, Owned}; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::io::Read; | use std::io::Read; | ||||||
| use std::raw::TraitObject; | use std::raw::TraitObject; | ||||||
| use std::str::from_utf8; |  | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::collections::hash_map::{Iter, Entry}; | use std::collections::hash_map::{Iter, Entry}; | ||||||
| use std::iter::{FromIterator, IntoIterator}; | use std::iter::{FromIterator, IntoIterator}; | ||||||
| use std::borrow::{Cow, IntoCow}; | use std::borrow::{Cow, IntoCow}; | ||||||
| use std::{mem, raw}; | use std::{mem, raw}; | ||||||
|  |  | ||||||
| use uany::{UnsafeAnyExt}; |  | ||||||
| use unicase::UniCase; | use unicase::UniCase; | ||||||
|  |  | ||||||
| use self::cell::OptCell; | use self::internals::Item; | ||||||
| use {http, HttpResult, HttpError}; | use {http, HttpResult, HttpError}; | ||||||
|  |  | ||||||
| pub use self::shared::{Encoding, EntityTag, Quality, QualityItem, qitem}; | pub use self::shared::{Encoding, EntityTag, Quality, QualityItem, qitem}; | ||||||
| pub use self::common::*; | pub use self::common::*; | ||||||
|  |  | ||||||
| mod cell; |  | ||||||
| mod common; | mod common; | ||||||
|  | mod internals; | ||||||
| mod shared; | mod shared; | ||||||
| pub mod parsing; | pub mod parsing; | ||||||
|  |  | ||||||
| @@ -55,7 +53,7 @@ pub trait Header: Clone + Any + Send + Sync { | |||||||
| /// A trait for any object that will represent a header field and value. | /// 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. | /// This trait represents the formatting of a Header for output to a TcpStream. | ||||||
| pub trait HeaderFormat: HeaderClone + Any + Send + Sync { | pub trait HeaderFormat: fmt::Debug + HeaderClone + Any + Send + Sync { | ||||||
|     /// Format a header to be output into a TcpStream. |     /// Format a header to be output into a TcpStream. | ||||||
|     /// |     /// | ||||||
|     /// This method is not allowed to introduce an Err not produced |     /// This method is not allowed to introduce an Err not produced | ||||||
| @@ -77,13 +75,6 @@ impl<T: HeaderFormat + Send + Sync + Clone> HeaderClone for T { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl HeaderFormat { | impl HeaderFormat { | ||||||
|     #[inline] |  | ||||||
|     fn is<T: 'static>(&self) -> bool { |  | ||||||
|         self.get_type_id() == TypeId::of::<T>() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl UnsafeAnyExt for HeaderFormat { |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { |     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { | ||||||
|         mem::transmute(mem::transmute::<&HeaderFormat, raw::TraitObject>(self).data) |         mem::transmute(mem::transmute::<&HeaderFormat, raw::TraitObject>(self).data) | ||||||
| @@ -93,11 +84,6 @@ impl UnsafeAnyExt for HeaderFormat { | |||||||
|     unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T { |     unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T { | ||||||
|         mem::transmute(mem::transmute::<&mut HeaderFormat, raw::TraitObject>(self).data) |         mem::transmute(mem::transmute::<&mut HeaderFormat, raw::TraitObject>(self).data) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     unsafe fn downcast_unchecked<T: 'static>(self: Box<HeaderFormat>) -> Box<T> { |  | ||||||
|         mem::transmute(mem::transmute::<Box<HeaderFormat>, raw::TraitObject>(self).data) |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Clone for Box<HeaderFormat + Send + Sync> { | impl Clone for Box<HeaderFormat + Send + Sync> { | ||||||
| @@ -179,19 +165,8 @@ impl Headers { | |||||||
|     /// ``` |     /// ``` | ||||||
|     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { |     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { | ||||||
|         self.data |         self.data | ||||||
|             // FIXME(reem): Find a better way to do this lookup without find_equiv. |  | ||||||
|             .get(&UniCase(Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) |             .get(&UniCase(Borrowed(unsafe { mem::transmute::<&str, &str>(name) }))) | ||||||
|             .and_then(|item| { |             .map(Item::raw) | ||||||
|                 if let Some(ref raw) = *item.raw { |  | ||||||
|                     return Some(&raw[..]); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 let raw = vec![item.typed.as_ref().unwrap().to_string().into_bytes()]; |  | ||||||
|                 item.raw.set(raw); |  | ||||||
|  |  | ||||||
|                 let raw = item.raw.as_ref().unwrap(); |  | ||||||
|                 Some(&raw[..]) |  | ||||||
|             }) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Set the raw value of a header, bypassing any typed headers. |     /// Set the raw value of a header, bypassing any typed headers. | ||||||
| @@ -214,26 +189,12 @@ impl Headers { | |||||||
|  |  | ||||||
|     /// Get a reference to the header field's value, if it exists. |     /// 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 + HeaderFormat>(&self) -> Option<&H> { | ||||||
|         self.get_or_parse::<H>().map(|item| { |         self.data.get(&UniCase(Borrowed(header_name::<H>()))).and_then(Item::typed::<H>) | ||||||
|             unsafe { |  | ||||||
|                 downcast(&*item) |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get a mutable reference to the header field's value, if it exists. |     /// 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 + HeaderFormat>(&mut self) -> Option<&mut H> { | ||||||
|         self.get_or_parse_mut::<H>().map(|item| { |         self.data.get_mut(&UniCase(Borrowed(header_name::<H>()))).and_then(Item::typed_mut::<H>) | ||||||
|             unsafe { downcast_mut(item) } |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&Item> { |  | ||||||
|         self.data.get(&UniCase(Borrowed(header_name::<H>()))).and_then(get_or_parse::<H>) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn get_or_parse_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut Item> { |  | ||||||
|         self.data.get_mut(&UniCase(Borrowed(header_name::<H>()))).and_then(get_or_parse_mut::<H>) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns a boolean of whether a certain header is in the map. |     /// Returns a boolean of whether a certain header is in the map. | ||||||
| @@ -329,11 +290,7 @@ impl<'a> HeaderView<'a> { | |||||||
|     /// Cast the value to a certain Header type. |     /// Cast the value to a certain Header type. | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> { |     pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> { | ||||||
|         get_or_parse::<H>(self.1).map(|item| { |         self.1.typed::<H>() | ||||||
|             unsafe { |  | ||||||
|                 downcast(&*item) |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get just the header value as a String. |     /// Get just the header value as a String. | ||||||
| @@ -371,141 +328,7 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) { | ||||||
| struct Item { |  | ||||||
|     raw: OptCell<Vec<Vec<u8>>>, |  | ||||||
|     typed: OptCell<Box<HeaderFormat + Send + Sync>> |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl Item { |  | ||||||
|     #[inline] |  | ||||||
|     fn new_raw(data: Vec<Vec<u8>>) -> Item { |  | ||||||
|         Item { |  | ||||||
|             raw: OptCell::new(Some(data)), |  | ||||||
|             typed: OptCell::new(None), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     fn new_typed(ty: Box<HeaderFormat + Send + Sync>) -> Item { |  | ||||||
|         Item { |  | ||||||
|             raw: OptCell::new(None), |  | ||||||
|             typed: OptCell::new(Some(ty)), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     fn mut_raw(&mut self) -> &mut Vec<Vec<u8>> { |  | ||||||
|         self.typed = OptCell::new(None); |  | ||||||
|         unsafe { |  | ||||||
|             self.raw.get_mut() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     #[inline] |  | ||||||
|     fn mut_typed(&mut self) -> &mut Box<HeaderFormat + Send + Sync> { |  | ||||||
|         self.raw = OptCell::new(None); |  | ||||||
|         unsafe { |  | ||||||
|             self.typed.get_mut() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| fn get_or_parse<H: Header + HeaderFormat>(item: &Item) -> Option<&Item> { |  | ||||||
|     match *item.typed { |  | ||||||
|         Some(ref typed) if typed.is::<H>() => return Some(item), |  | ||||||
|         Some(ref typed) => { |  | ||||||
|             warn!("attempted to access {:?} as wrong type", typed); |  | ||||||
|             return None; |  | ||||||
|         } |  | ||||||
|         _ => () |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     parse::<H>(item); |  | ||||||
|     if item.typed.is_some() { |  | ||||||
|         Some(item) |  | ||||||
|     } else { |  | ||||||
|         None |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn get_or_parse_mut<H: Header + HeaderFormat>(item: &mut Item) -> Option<&mut Item> { |  | ||||||
|     let is_correct_type = match *item.typed { |  | ||||||
|         Some(ref typed) if typed.is::<H>() => 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::<H>(&item); |  | ||||||
|     if item.typed.is_some() { |  | ||||||
|         Some(item) |  | ||||||
|     } else { |  | ||||||
|         None |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn parse<H: Header + HeaderFormat>(item: &Item) { |  | ||||||
|     match *item.raw { |  | ||||||
|         Some(ref raw) => match Header::parse_header(&raw[..]) { |  | ||||||
|             Some::<H>(h) => item.typed.set(box h as Box<HeaderFormat + Send + Sync>), |  | ||||||
|             None => () |  | ||||||
|         }, |  | ||||||
|         None => unreachable!() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[inline] |  | ||||||
| unsafe fn downcast<H: Header + HeaderFormat>(item: &Item) -> &H { |  | ||||||
|     item.typed.as_ref().expect("item.typed must be set").downcast_ref_unchecked() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[inline] |  | ||||||
| unsafe fn downcast_mut<H: Header + HeaderFormat>(item: &mut Item) -> &mut H { |  | ||||||
|     item.mut_typed().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<HeaderFormat + Send + Sync> { |  | ||||||
|     #[inline] |  | ||||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |  | ||||||
|         (**self).fmt_header(fmt) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl fmt::Display for Box<HeaderFormat + Send + Sync> { |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|         (**self).fmt_header(fmt) |         (**self).fmt_header(fmt) | ||||||
| @@ -568,7 +391,7 @@ mod tests { | |||||||
|         assert_eq!(accept, Some(Accept(vec![application_vendor, text_plain]))); |         assert_eq!(accept, Some(Accept(vec![application_vendor, text_plain]))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[derive(Clone, Debug)] |     #[derive(Clone, PartialEq, Debug)] | ||||||
|     struct CrazyLength(Option<bool>, usize); |     struct CrazyLength(Option<bool>, usize); | ||||||
|  |  | ||||||
|     impl Header for CrazyLength { |     impl Header for CrazyLength { | ||||||
| @@ -600,15 +423,14 @@ mod tests { | |||||||
|     #[test] |     #[test] | ||||||
|     fn test_different_structs_for_same_header() { |     fn test_different_structs_for_same_header() { | ||||||
|         let headers = Headers::from_raw(&mut b"Content-Length: 10\r\n\r\n").unwrap(); |         let headers = Headers::from_raw(&mut b"Content-Length: 10\r\n\r\n").unwrap(); | ||||||
|         let ContentLength(_) = *headers.get::<ContentLength>().unwrap(); |         assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10))); | ||||||
|         assert!(headers.get::<CrazyLength>().is_none()); |         assert_eq!(headers.get::<CrazyLength>(), Some(&CrazyLength(Some(false), 10))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_trailing_whitespace() { |     fn test_trailing_whitespace() { | ||||||
|         let headers = Headers::from_raw(&mut b"Content-Length: 10   \r\n\r\n").unwrap(); |         let headers = Headers::from_raw(&mut b"Content-Length: 10   \r\n\r\n").unwrap(); | ||||||
|         let ContentLength(_) = *headers.get::<ContentLength>().unwrap(); |         assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10))); | ||||||
|         assert!(headers.get::<CrazyLength>().is_none()); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|   | |||||||
| @@ -130,7 +130,6 @@ extern crate "rustc-serialize" as serialize; | |||||||
| extern crate time; | extern crate time; | ||||||
| extern crate url; | extern crate url; | ||||||
| extern crate openssl; | extern crate openssl; | ||||||
| extern crate "unsafe-any" as uany; |  | ||||||
| extern crate cookie; | extern crate cookie; | ||||||
| extern crate unicase; | extern crate unicase; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,6 @@ use std::path::Path; | |||||||
| use std::raw::{self, TraitObject}; | use std::raw::{self, TraitObject}; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
|  |  | ||||||
| use uany::UnsafeAnyExt; |  | ||||||
| use openssl::ssl::{Ssl, SslStream, SslContext}; | use openssl::ssl::{Ssl, SslStream, SslContext}; | ||||||
| use openssl::ssl::SslVerifyMode::SslVerifyNone; | use openssl::ssl::SslVerifyMode::SslVerifyNone; | ||||||
| use openssl::ssl::SslMethod::Sslv23; | use openssl::ssl::SslMethod::Sslv23; | ||||||
| @@ -99,7 +98,7 @@ impl Clone for Box<NetworkStream + Send> { | |||||||
|     fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() } |     fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl UnsafeAnyExt for NetworkStream { | impl NetworkStream { | ||||||
|     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { |     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { | ||||||
|         mem::transmute(mem::transmute::<&NetworkStream, |         mem::transmute(mem::transmute::<&NetworkStream, | ||||||
|                                         raw::TraitObject>(self).data) |                                         raw::TraitObject>(self).data) | ||||||
| @@ -351,8 +350,6 @@ fn lift_ssl_error(ssl: SslError) -> io::Error { | |||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use uany::UnsafeAnyExt; |  | ||||||
|  |  | ||||||
|     use mock::MockStream; |     use mock::MockStream; | ||||||
|     use super::NetworkStream; |     use super::NetworkStream; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user