diff --git a/Cargo.toml b/Cargo.toml index 1416e12de1..81e90fdfdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,10 +36,16 @@ optional = true version = "0.4" default-features = false +[dependencies.serde] +version = "*" +optional = true + [dev-dependencies] env_logger = "*" [features] default = ["ssl"] ssl = ["openssl", "cookie/secure"] +serde-serialization = ["serde"] nightly = [] + diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index c7c2c2913d..3ce8dbbac8 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -158,6 +158,31 @@ macro_rules! test_header { } } +#[macro_export] +macro_rules! __hyper_generate_header_serialization { + ($id:ident) => { + #[cfg(feature = "serde-serialization")] + impl ::serde::Serialize for $id { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer { + format!("{}", self).serialize(serializer) + } + } + + #[cfg(feature = "serde-serialization")] + impl ::serde::Deserialize for $id { + fn deserialize(deserializer: &mut D) -> Result<$id, D::Error> + where D: ::serde::Deserializer { + let string_representation: String = + try!(::serde::Deserialize::deserialize(deserializer)); + Ok($crate::header::Header::parse_header(&[ + string_representation.into_bytes() + ]).unwrap()) + } + } + } +} + #[macro_export] macro_rules! header { // $a:meta: Attributes associated with the header item (usually docs) @@ -190,6 +215,8 @@ macro_rules! header { self.fmt_header(f) } } + + __hyper_generate_header_serialization!($id); }; // List header, one or more items ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => { @@ -216,6 +243,7 @@ macro_rules! header { self.fmt_header(f) } } + __hyper_generate_header_serialization!($id); }; // Single value header ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => { @@ -241,6 +269,7 @@ macro_rules! header { ::std::fmt::Display::fmt(&**self, f) } } + __hyper_generate_header_serialization!($id); }; // List header, one or more items with "*" option ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => { @@ -281,6 +310,7 @@ macro_rules! header { self.fmt_header(f) } } + __hyper_generate_header_serialization!($id); }; // optional test module diff --git a/src/header/mod.rs b/src/header/mod.rs index 7044d29fe5..f52038b877 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -92,6 +92,13 @@ use unicase::UniCase; use self::internals::Item; +#[cfg(feature = "serde-serialization")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "serde-serialization")] +use serde::de; +#[cfg(feature = "serde-serialization")] +use serde::ser; + pub use self::shared::*; pub use self::common::*; @@ -322,6 +329,65 @@ impl fmt::Debug for Headers { } } +#[cfg(feature = "serde-serialization")] +impl Serialize for Headers { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + struct HeadersVisitor<'a> { + iter: HeadersItems<'a>, + len: usize, + } + + impl<'a> ser::MapVisitor for HeadersVisitor<'a> { + fn visit(&mut self, serializer: &mut S) -> Result, S::Error> + where S: Serializer { + match self.iter.next() { + Some(header_item) => { + try!(serializer.visit_map_elt(header_item.name(), + header_item.value_string())); + Ok(Some(())) + } + None => Ok(None), + } + } + + fn len(&self) -> Option { + Some(self.len) + } + } + + serializer.visit_map(HeadersVisitor { + iter: self.iter(), + len: self.len(), + }) + } +} + +#[cfg(feature = "serde-serialization")] +impl Deserialize for Headers { + fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { + struct HeadersVisitor; + + impl de::Visitor for HeadersVisitor { + type Value = Headers; + + fn visit_map(&mut self, mut visitor: V) -> Result + where V: de::MapVisitor { + let mut result = Headers::new(); + while let Some((key, value)) = try!(visitor.visit()) { + let (key, value): (String, String) = (key, value); + result.set_raw(key, vec![value.into_bytes()]); + } + try!(visitor.end()); + Ok(result) + } + } + + let result = Headers::new(); + try!(deserializer.visit_map(HeadersVisitor)); + Ok(result) + } +} + /// An `Iterator` over the fields in a `Headers` map. pub struct HeadersItems<'a> { inner: Iter<'a, HeaderName, Item> diff --git a/src/http/mod.rs b/src/http/mod.rs index a52f2023ec..0133bf25f8 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -7,6 +7,9 @@ use header::Headers; use version::HttpVersion; use version::HttpVersion::{Http10, Http11}; +#[cfg(feature = "serde-serialization")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + pub use self::message::{HttpMessage, RequestHead, ResponseHead, Protocol}; pub mod h1; @@ -17,6 +20,21 @@ pub mod message; #[derive(Clone, PartialEq, Debug)] pub struct RawStatus(pub u16, pub Cow<'static, str>); +#[cfg(feature = "serde-serialization")] +impl Serialize for RawStatus { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + (self.0, self.1.clone().into_owned()).serialize(serializer) + } +} + +#[cfg(feature = "serde-serialization")] +impl Deserialize for RawStatus { + fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { + let representation: (u16, String) = try!(Deserialize::deserialize(deserializer)); + Ok(RawStatus(representation.0, Cow::Owned(representation.1))) + } +} + /// Checks if a connection should be kept alive. #[inline] pub fn should_keep_alive(version: HttpVersion, headers: &Headers) -> bool { diff --git a/src/lib.rs b/src/lib.rs index 0abe385ddd..60fde80c11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,6 +133,8 @@ extern crate time; extern crate url; #[cfg(feature = "openssl")] extern crate openssl; +#[cfg(feature = "serde-serialization")] +extern crate serde; extern crate cookie; extern crate unicase; extern crate httparse; diff --git a/src/method.rs b/src/method.rs index 1ab7cf137a..10d5569119 100644 --- a/src/method.rs +++ b/src/method.rs @@ -7,6 +7,9 @@ use error::Error; use self::Method::{Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch, Extension}; +#[cfg(feature = "serde-serialization")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + /// The Request Method (VERB) /// /// Currently includes 8 variants representing the 8 methods defined in @@ -125,6 +128,21 @@ impl fmt::Display for Method { } } +#[cfg(feature = "serde-serialization")] +impl Serialize for Method { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + format!("{}", self).serialize(serializer) + } +} + +#[cfg(feature = "serde-serialization")] +impl Deserialize for Method { + fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { + let string_representation: String = try!(Deserialize::deserialize(deserializer)); + Ok(FromStr::from_str(&string_representation[..]).unwrap()) + } +} + #[cfg(test)] mod tests { use std::collections::HashMap;