Merge pull request #358 from hyperium/reparsing
feat(headers): adds re-parsing ability when getting typed headers
This commit is contained in:
		| @@ -19,5 +19,4 @@ openssl = "*" | ||||
| rustc-serialize = "*" | ||||
| time = "*" | ||||
| unicase = "*" | ||||
| unsafe-any = "*" | ||||
| url = "*" | ||||
|   | ||||
| @@ -50,7 +50,7 @@ impl Write for MockStream { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| #[derive(Clone, Debug)] | ||||
| struct 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. | ||||
| pub trait Scheme: FromStr + Clone + Send + Sync { | ||||
| pub trait Scheme: FromStr + fmt::Debug + Clone + Send + Sync { | ||||
|     /// An optional Scheme name. | ||||
|     /// | ||||
|     /// 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 | ||||
| //! 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::any::Any; | ||||
| use std::borrow::Cow::{Borrowed, Owned}; | ||||
| use std::fmt; | ||||
| use std::io::Read; | ||||
| use std::raw::TraitObject; | ||||
| use std::str::from_utf8; | ||||
| use std::collections::HashMap; | ||||
| use std::collections::hash_map::{Iter, Entry}; | ||||
| use std::iter::{FromIterator, IntoIterator}; | ||||
| use std::borrow::{Cow, IntoCow}; | ||||
| use std::{mem, raw}; | ||||
|  | ||||
| use uany::{UnsafeAnyExt}; | ||||
| use unicase::UniCase; | ||||
|  | ||||
| use self::cell::OptCell; | ||||
| use self::internals::Item; | ||||
| use {http, HttpResult, HttpError}; | ||||
|  | ||||
| pub use self::shared::{Charset, Encoding, EntityTag, Quality, QualityItem, qitem, q}; | ||||
| pub use self::common::*; | ||||
|  | ||||
| mod cell; | ||||
| mod common; | ||||
| mod internals; | ||||
| mod shared; | ||||
| 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. | ||||
| /// | ||||
| /// 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. | ||||
|     /// | ||||
|     /// 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 { | ||||
|     #[inline] | ||||
|     fn is<T: 'static>(&self) -> bool { | ||||
|         self.get_type_id() == TypeId::of::<T>() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl UnsafeAnyExt for HeaderFormat { | ||||
|     #[inline] | ||||
|     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { | ||||
|         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 { | ||||
|         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> { | ||||
| @@ -179,19 +165,8 @@ impl Headers { | ||||
|     /// ``` | ||||
|     pub fn get_raw(&self, name: &str) -> Option<&[Vec<u8>]> { | ||||
|         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.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[..]) | ||||
|             }) | ||||
|             .map(Item::raw) | ||||
|     } | ||||
|  | ||||
|     /// 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. | ||||
|     pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> { | ||||
|         self.get_or_parse::<H>().map(|item| { | ||||
|             unsafe { | ||||
|                 downcast(&*item) | ||||
|             } | ||||
|         }) | ||||
|         self.data.get(&UniCase(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> { | ||||
|         self.get_or_parse_mut::<H>().map(|item| { | ||||
|             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>) | ||||
|         self.data.get_mut(&UniCase(Borrowed(header_name::<H>()))).and_then(Item::typed_mut::<H>) | ||||
|     } | ||||
|  | ||||
|     /// 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. | ||||
|     #[inline] | ||||
|     pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> { | ||||
|         get_or_parse::<H>(self.1).map(|item| { | ||||
|             unsafe { | ||||
|                 downcast(&*item) | ||||
|             } | ||||
|         }) | ||||
|         self.1.typed::<H>() | ||||
|     } | ||||
|  | ||||
|     /// Get just the header value as a String. | ||||
| @@ -371,141 +328,7 @@ impl<'a> FromIterator<HeaderView<'a>> for Headers { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Clone)] | ||||
| 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> { | ||||
| impl<'a> fmt::Display for &'a (HeaderFormat + Send + Sync) { | ||||
|     #[inline] | ||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||
|         (**self).fmt_header(fmt) | ||||
| @@ -568,7 +391,7 @@ mod tests { | ||||
|         assert_eq!(accept, Some(Accept(vec![application_vendor, text_plain]))); | ||||
|     } | ||||
|  | ||||
|     #[derive(Clone, Debug)] | ||||
|     #[derive(Clone, PartialEq, Debug)] | ||||
|     struct CrazyLength(Option<bool>, usize); | ||||
|  | ||||
|     impl Header for CrazyLength { | ||||
| @@ -600,15 +423,14 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_different_structs_for_same_header() { | ||||
|         let headers = Headers::from_raw(&mut b"Content-Length: 10\r\n\r\n").unwrap(); | ||||
|         let ContentLength(_) = *headers.get::<ContentLength>().unwrap(); | ||||
|         assert!(headers.get::<CrazyLength>().is_none()); | ||||
|         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(&mut b"Content-Length: 10   \r\n\r\n").unwrap(); | ||||
|         let ContentLength(_) = *headers.get::<ContentLength>().unwrap(); | ||||
|         assert!(headers.get::<CrazyLength>().is_none()); | ||||
|         assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(10))); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|   | ||||
| @@ -130,7 +130,6 @@ extern crate "rustc-serialize" as serialize; | ||||
| extern crate time; | ||||
| extern crate url; | ||||
| extern crate openssl; | ||||
| extern crate "unsafe-any" as uany; | ||||
| extern crate cookie; | ||||
| extern crate unicase; | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,6 @@ use std::path::Path; | ||||
| use std::raw::{self, TraitObject}; | ||||
| use std::sync::Arc; | ||||
|  | ||||
| use uany::UnsafeAnyExt; | ||||
| use openssl::ssl::{Ssl, SslStream, SslContext}; | ||||
| use openssl::ssl::SslVerifyMode::SslVerifyNone; | ||||
| use openssl::ssl::SslMethod::Sslv23; | ||||
| @@ -99,7 +98,7 @@ impl Clone for Box<NetworkStream + Send> { | ||||
|     fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() } | ||||
| } | ||||
|  | ||||
| impl UnsafeAnyExt for NetworkStream { | ||||
| impl NetworkStream { | ||||
|     unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T { | ||||
|         mem::transmute(mem::transmute::<&NetworkStream, | ||||
|                                         raw::TraitObject>(self).data) | ||||
| @@ -351,8 +350,6 @@ fn lift_ssl_error(ssl: SslError) -> io::Error { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use uany::UnsafeAnyExt; | ||||
|  | ||||
|     use mock::MockStream; | ||||
|     use super::NetworkStream; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user