diff --git a/src/header/mod.rs b/src/header/mod.rs index c4ce71fc..915c1312 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -13,6 +13,7 @@ use std::raw::TraitObject; use std::str::{from_utf8, SendStr, Slice, Owned}; use std::string::raw; use std::collections::hashmap::{HashMap, Entries, Occupied, Vacant}; +use std::sync::RWLock; use uany::UncheckedAnyDowncast; use typeable::Typeable; @@ -24,7 +25,7 @@ use {HttpResult}; pub mod common; /// A trait for any object that will represent a header field and value. -pub trait Header: Typeable { +pub trait Header: Typeable + Send + Sync { /// Returns the name of the header field this belongs to. /// /// The market `Option` is to hint to the type system which implementation @@ -68,7 +69,7 @@ fn header_name() -> &'static str { /// A map of header fields on requests and responses. pub struct Headers { - data: HashMap + data: HashMap> } impl Headers { @@ -92,13 +93,14 @@ impl Headers { raw::from_utf8(name) }; - let item = match headers.data.entry(CaseInsensitive(Owned(name))) { - Vacant(entry) => entry.set(Raw(vec![])), + let name = CaseInsensitive(Owned(name)); + let item = match headers.data.entry(name) { + Vacant(entry) => entry.set(RWLock::new(Raw(vec![]))), Occupied(entry) => entry.into_mut() }; - match *item { - Raw(ref mut raw) => raw.push(value), + match &mut *item.write() { + &Raw(ref mut raw) => raw.push(value), // Unreachable _ => {} }; @@ -113,7 +115,7 @@ impl Headers { /// /// The field is determined by the type of the value being set. pub fn set(&mut self, value: H) { - self.data.insert(CaseInsensitive(Slice(header_name::())), Typed(box value as Box
)); + self.data.insert(CaseInsensitive(Slice(header_name::())), RWLock::new(Typed(box value as Box
))); } /// Get a clone of the header field's value, if it exists. @@ -126,7 +128,7 @@ impl Headers { /// # let mut headers = Headers::new(); /// let content_type = headers.get::(); /// ``` - pub fn get(&mut self) -> Option { + pub fn get(&self) -> Option { self.get_ref().map(|v: &H| v.clone()) } @@ -136,26 +138,29 @@ impl Headers { /// If the header field has already been parsed into a typed header, /// then you *must* access it through that representation. /// + /// This operation is unsafe because the raw representation can be + /// invalidated by lasting too long or by the header being parsed + /// while you still have a reference to the data. + /// /// Example: /// ``` /// # use hyper::header::Headers; /// # let mut headers = Headers::new(); /// let raw_content_type = unsafe { headers.get_raw("content-type") }; /// ``` - pub unsafe fn get_raw(&self, name: &'static str) -> Option<&[Vec]> { + pub unsafe fn get_raw(&self, name: &'static str) -> Option<*const [Vec]> { self.data.find(&CaseInsensitive(Slice(name))).and_then(|item| { - match *item { - Raw(ref raw) => Some(raw.as_slice()), + match *item.read() { + Raw(ref raw) => Some(raw.as_slice() as *const [Vec]), _ => None } }) } /// Get a reference to the header field's value, if it exists. - pub fn get_ref(&mut self) -> Option<&H> { - self.data.find_mut(&CaseInsensitive(Slice(header_name::()))).and_then(|item| { - debug!("get_ref, name={}, val={}", header_name::(), item); - let header = match *item { + pub fn get_ref(&self) -> Option<&H> { + self.data.find(&CaseInsensitive(Slice(header_name::()))).and_then(|item| { + let header = match *item.read() { // Huge borrowck hack here, should be refactored to just return here. Typed(ref typed) if typed.is::() => None, // Typed, wrong type @@ -170,7 +175,7 @@ impl Headers { match header { Some(header) => { - *item = Typed(box header as Box
); + *item.write() = Typed(box header as Box
); Some(item) }, None => { @@ -178,14 +183,15 @@ impl Headers { } } }).and_then(|item| { - debug!("downcasting {}", item); - let ret = match *item { + let read = item.read(); + debug!("downcasting {}", *read); + let ret = match *read { Typed(ref val) => { unsafe { Some(val.downcast_ref_unchecked()) } }, _ => unreachable!() }; - ret + unsafe { transmute::, Option<&H>>(ret) } }) } @@ -229,7 +235,7 @@ impl fmt::Show for Headers { /// An `Iterator` over the fields in a `Headers` map. pub struct HeadersItems<'a> { - inner: Entries<'a, CaseInsensitive, Item> + inner: Entries<'a, CaseInsensitive, RWLock> } impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> { @@ -242,12 +248,12 @@ impl<'a> Iterator<(&'a str, HeaderView<'a>)> for HeadersItems<'a> { } /// Returned with the `HeadersItems` iterator. -pub struct HeaderView<'a>(&'a Item); +pub struct HeaderView<'a>(&'a RWLock); impl<'a> fmt::Show for HeaderView<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let HeaderView(item) = *self; - item.fmt(fmt) + item.read().fmt(fmt) } } @@ -265,7 +271,7 @@ impl Mutable for Headers { enum Item { Raw(Vec>), - Typed(Box
) + Typed(Box
) } impl fmt::Show for Item { @@ -341,7 +347,7 @@ mod tests { #[test] fn test_from_raw() { - let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); + let headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); assert_eq!(headers.get_ref(), Some(&ContentLength(10))); } @@ -380,8 +386,9 @@ mod tests { #[test] fn test_different_structs_for_same_header() { - let mut headers = Headers::from_raw(&mut mem("Content-Length: 10\r\n\r\n")).unwrap(); + 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()); } } +