feat(http): add optional serialization of common types via serde
				
					
				
			This is behind a Cargo feature to avoid forcing downstream users to depend on `serde`. It is needed for Servo IPC to work.
This commit is contained in:
		| @@ -36,10 +36,16 @@ optional = true | |||||||
| version = "0.4" | version = "0.4" | ||||||
| default-features = false | default-features = false | ||||||
|  |  | ||||||
|  | [dependencies.serde] | ||||||
|  | version = "*" | ||||||
|  | optional = true | ||||||
|  |  | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
| env_logger = "*" | env_logger = "*" | ||||||
|  |  | ||||||
| [features] | [features] | ||||||
| default = ["ssl"] | default = ["ssl"] | ||||||
| ssl = ["openssl", "cookie/secure"] | ssl = ["openssl", "cookie/secure"] | ||||||
|  | serde-serialization = ["serde"] | ||||||
| nightly = [] | nightly = [] | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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<S>(&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<D>(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_export] | ||||||
| macro_rules! header { | macro_rules! header { | ||||||
|     // $a:meta: Attributes associated with the header item (usually docs) |     // $a:meta: Attributes associated with the header item (usually docs) | ||||||
| @@ -190,6 +215,8 @@ macro_rules! header { | |||||||
|                 self.fmt_header(f) |                 self.fmt_header(f) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         __hyper_generate_header_serialization!($id); | ||||||
|     }; |     }; | ||||||
|     // List header, one or more items |     // List header, one or more items | ||||||
|     ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => { |     ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => { | ||||||
| @@ -216,6 +243,7 @@ macro_rules! header { | |||||||
|                 self.fmt_header(f) |                 self.fmt_header(f) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         __hyper_generate_header_serialization!($id); | ||||||
|     }; |     }; | ||||||
|     // Single value header |     // Single value header | ||||||
|     ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => { |     ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => { | ||||||
| @@ -241,6 +269,7 @@ macro_rules! header { | |||||||
|                 ::std::fmt::Display::fmt(&**self, f) |                 ::std::fmt::Display::fmt(&**self, f) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         __hyper_generate_header_serialization!($id); | ||||||
|     }; |     }; | ||||||
|     // List header, one or more items with "*" option |     // List header, one or more items with "*" option | ||||||
|     ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => { |     ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => { | ||||||
| @@ -281,6 +310,7 @@ macro_rules! header { | |||||||
|                 self.fmt_header(f) |                 self.fmt_header(f) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         __hyper_generate_header_serialization!($id); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     // optional test module |     // optional test module | ||||||
|   | |||||||
| @@ -92,6 +92,13 @@ use unicase::UniCase; | |||||||
|  |  | ||||||
| use self::internals::Item; | 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::shared::*; | ||||||
| pub use self::common::*; | pub use self::common::*; | ||||||
|  |  | ||||||
| @@ -322,6 +329,65 @@ impl fmt::Debug for Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | impl Serialize for Headers { | ||||||
|  |     fn serialize<S>(&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<S>(&mut self, serializer: &mut S) -> Result<Option<()>, 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<usize> { | ||||||
|  |                 Some(self.len) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         serializer.visit_map(HeadersVisitor { | ||||||
|  |             iter: self.iter(), | ||||||
|  |             len: self.len(), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | impl Deserialize for Headers { | ||||||
|  |     fn deserialize<D>(deserializer: &mut D) -> Result<Headers, D::Error> where D: Deserializer { | ||||||
|  |         struct HeadersVisitor; | ||||||
|  |  | ||||||
|  |         impl de::Visitor for HeadersVisitor { | ||||||
|  |             type Value = Headers; | ||||||
|  |  | ||||||
|  |             fn visit_map<V>(&mut self, mut visitor: V) -> Result<Headers, V::Error> | ||||||
|  |                             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. | /// An `Iterator` over the fields in a `Headers` map. | ||||||
| pub struct HeadersItems<'a> { | pub struct HeadersItems<'a> { | ||||||
|     inner: Iter<'a, HeaderName, Item> |     inner: Iter<'a, HeaderName, Item> | ||||||
|   | |||||||
| @@ -7,6 +7,9 @@ use header::Headers; | |||||||
| use version::HttpVersion; | use version::HttpVersion; | ||||||
| use version::HttpVersion::{Http10, Http11}; | use version::HttpVersion::{Http10, Http11}; | ||||||
|  |  | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||||||
|  |  | ||||||
| pub use self::message::{HttpMessage, RequestHead, ResponseHead, Protocol}; | pub use self::message::{HttpMessage, RequestHead, ResponseHead, Protocol}; | ||||||
|  |  | ||||||
| pub mod h1; | pub mod h1; | ||||||
| @@ -17,6 +20,21 @@ pub mod message; | |||||||
| #[derive(Clone, PartialEq, Debug)] | #[derive(Clone, PartialEq, Debug)] | ||||||
| pub struct RawStatus(pub u16, pub Cow<'static, str>); | pub struct RawStatus(pub u16, pub Cow<'static, str>); | ||||||
|  |  | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | impl Serialize for RawStatus { | ||||||
|  |     fn serialize<S>(&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<D>(deserializer: &mut D) -> Result<RawStatus, D::Error> 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. | /// Checks if a connection should be kept alive. | ||||||
| #[inline] | #[inline] | ||||||
| pub fn should_keep_alive(version: HttpVersion, headers: &Headers) -> bool { | pub fn should_keep_alive(version: HttpVersion, headers: &Headers) -> bool { | ||||||
|   | |||||||
| @@ -133,6 +133,8 @@ extern crate time; | |||||||
| extern crate url; | extern crate url; | ||||||
| #[cfg(feature = "openssl")] | #[cfg(feature = "openssl")] | ||||||
| extern crate openssl; | extern crate openssl; | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | extern crate serde; | ||||||
| extern crate cookie; | extern crate cookie; | ||||||
| extern crate unicase; | extern crate unicase; | ||||||
| extern crate httparse; | extern crate httparse; | ||||||
|   | |||||||
| @@ -7,6 +7,9 @@ use error::Error; | |||||||
| use self::Method::{Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch, | use self::Method::{Options, Get, Post, Put, Delete, Head, Trace, Connect, Patch, | ||||||
|                    Extension}; |                    Extension}; | ||||||
|  |  | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||||||
|  |  | ||||||
| /// The Request Method (VERB) | /// The Request Method (VERB) | ||||||
| /// | /// | ||||||
| /// Currently includes 8 variants representing the 8 methods defined in | /// 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<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { | ||||||
|  |         format!("{}", self).serialize(serializer) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[cfg(feature = "serde-serialization")] | ||||||
|  | impl Deserialize for Method { | ||||||
|  |     fn deserialize<D>(deserializer: &mut D) -> Result<Method, D::Error> where D: Deserializer { | ||||||
|  |         let string_representation: String = try!(Deserialize::deserialize(deserializer)); | ||||||
|  |         Ok(FromStr::from_str(&string_representation[..]).unwrap()) | ||||||
|  |     } | ||||||
|  | }  | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use std::collections::HashMap; |     use std::collections::HashMap; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user