Merge pull request #421 from pyfisch/refactorheaders3
refactor(headers): Use header!() macro for 3 headers with a "*" value
This commit is contained in:
		| @@ -1,51 +1,31 @@ | |||||||
| use header::{EntityTag, Header, HeaderFormat}; | use header::EntityTag; | ||||||
| use header::parsing::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str}; |  | ||||||
| use std::fmt; |  | ||||||
|  |  | ||||||
| /// The `If-Match` header | header! { | ||||||
| /// |     #[doc="`If-Match` header, defined in"] | ||||||
| /// The `If-Match` request-header field is used with a method to make |     #[doc="[RFC7232](https://tools.ietf.org/html/rfc7232#section-3.1)"] | ||||||
| /// it conditional.  The client provides a list of entity tags, and |     #[doc=""] | ||||||
| /// the request is only executed if one of those tags matches the |     #[doc="The `If-Match` header field makes the request method conditional on"] | ||||||
| /// current entity. |     #[doc="the recipient origin server either having at least one current"] | ||||||
| /// |     #[doc="representation of the target resource, when the field-value is \"*\","] | ||||||
| /// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24 |     #[doc="or having a current representation of the target resource that has an"] | ||||||
| #[derive(Clone, PartialEq, Debug)] |     #[doc="entity-tag matching a member of the list of entity-tags provided in"] | ||||||
| pub enum IfMatch { |     #[doc="the field-value."] | ||||||
|     /// This corresponds to '*'. |     #[doc=""] | ||||||
|     Any, |     #[doc="An origin server MUST use the strong comparison function when"] | ||||||
|     /// The header field names which will influence the response representation. |     #[doc="comparing entity-tags for `If-Match`, since the client"] | ||||||
|     EntityTags(Vec<EntityTag>) |     #[doc="intends this precondition to prevent the method from being applied if"] | ||||||
| } |     #[doc="there have been any changes to the representation data."] | ||||||
|  |     #[doc=""] | ||||||
| impl Header for IfMatch { |     #[doc="# ABNF"] | ||||||
|     fn header_name() -> &'static str { |     #[doc="```plain"] | ||||||
|         "If-Match" |     #[doc="If-Match = \"*\" / 1#entity-tag"] | ||||||
|     } |     #[doc="```"] | ||||||
|  |     (IfMatch, "If-Match") => {Any / (EntityTag)+} | ||||||
|     fn parse_header(raw: &[Vec<u8>]) -> Option<IfMatch> { |  | ||||||
|         from_one_raw_str(raw).and_then(|s: String| { |  | ||||||
|             let slice = &s[..]; |  | ||||||
|             match slice { |  | ||||||
|                 "" => None, |  | ||||||
|                 "*" => Some(IfMatch::Any), |  | ||||||
|                 _ => from_comma_delimited(raw).map(IfMatch::EntityTags), |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl HeaderFormat for IfMatch { |  | ||||||
|     fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |  | ||||||
|         match *self { |  | ||||||
|             IfMatch::Any => write!(fmt, "*"), |  | ||||||
|             IfMatch::EntityTags(ref fields) => fmt_comma_delimited(fmt, &fields[..]) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn test_parse_header() { | fn test_parse_header() { | ||||||
|  |     use header::Header; | ||||||
|     { |     { | ||||||
|         let a: IfMatch = Header::parse_header( |         let a: IfMatch = Header::parse_header( | ||||||
|         [b"*".to_vec()].as_ref()).unwrap(); |         [b"*".to_vec()].as_ref()).unwrap(); | ||||||
| @@ -54,7 +34,7 @@ fn test_parse_header() { | |||||||
|     { |     { | ||||||
|         let a: IfMatch = Header::parse_header( |         let a: IfMatch = Header::parse_header( | ||||||
|             [b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"".to_vec()].as_ref()).unwrap(); |             [b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\"".to_vec()].as_ref()).unwrap(); | ||||||
|         let b = IfMatch::EntityTags( |         let b = IfMatch::Items( | ||||||
|             vec![EntityTag::new(false, "xyzzy".to_string()), |             vec![EntityTag::new(false, "xyzzy".to_string()), | ||||||
|                  EntityTag::new(false, "r2d2xxxx".to_string()), |                  EntityTag::new(false, "r2d2xxxx".to_string()), | ||||||
|                  EntityTag::new(false, "c3piozzzz".to_string())]); |                  EntityTag::new(false, "c3piozzzz".to_string())]); | ||||||
|   | |||||||
| @@ -1,8 +1,28 @@ | |||||||
| use header::{Header, HeaderFormat, EntityTag}; | use header::EntityTag; | ||||||
| use header::parsing::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str}; |  | ||||||
| use std::fmt::{self}; |  | ||||||
|  |  | ||||||
| /// The `If-None-Match` header defined by HTTP/1.1. | header! { | ||||||
|  |     #[doc="`If-None-Match` header, defined in"] | ||||||
|  |     #[doc="[RFC7232](https://tools.ietf.org/html/rfc7232#section-3.2)"] | ||||||
|  |     #[doc=""] | ||||||
|  |     #[doc="The `If-None-Match` header field makes the request method conditional"] | ||||||
|  |     #[doc="on a recipient cache or origin server either not having any current"] | ||||||
|  |     #[doc="representation of the target resource, when the field-value is \"*\","] | ||||||
|  |     #[doc="or having a selected representation with an entity-tag that does not"] | ||||||
|  |     #[doc="match any of those listed in the field-value."] | ||||||
|  |     #[doc=""] | ||||||
|  |     #[doc="A recipient MUST use the weak comparison function when comparing"] | ||||||
|  |     #[doc="entity-tags for If-None-Match (Section 2.3.2), since weak entity-tags"] | ||||||
|  |     #[doc="can be used for cache validation even if there have been changes to"] | ||||||
|  |     #[doc="the representation data."] | ||||||
|  |     #[doc=""] | ||||||
|  |     #[doc="# ABNF"] | ||||||
|  |     #[doc="```plain"] | ||||||
|  |     #[doc="If-None-Match = \"*\" / 1#entity-tag"] | ||||||
|  |     #[doc="```"] | ||||||
|  |     (IfNoneMatch, "If-None-Match") => {Any / (EntityTag)+} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*/// The `If-None-Match` header defined by HTTP/1.1. | ||||||
| /// | /// | ||||||
| /// The "If-None-Match" header field makes the request method conditional | /// The "If-None-Match" header field makes the request method conditional | ||||||
| /// on a recipient cache or origin server either not having any current | /// on a recipient cache or origin server either not having any current | ||||||
| @@ -50,7 +70,7 @@ impl HeaderFormat for IfNoneMatch { | |||||||
|             IfNoneMatch::EntityTags(ref fields) => { fmt_comma_delimited(fmt, &fields[..]) } |             IfNoneMatch::EntityTags(ref fields) => { fmt_comma_delimited(fmt, &fields[..]) } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | }*/ | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
| @@ -71,7 +91,7 @@ mod tests { | |||||||
|         let weak_etag = EntityTag::new(true, "weak-etag".to_string()); |         let weak_etag = EntityTag::new(true, "weak-etag".to_string()); | ||||||
|         entities.push(foobar_etag); |         entities.push(foobar_etag); | ||||||
|         entities.push(weak_etag); |         entities.push(weak_etag); | ||||||
|         assert_eq!(if_none_match, Some(IfNoneMatch::EntityTags(entities))); |         assert_eq!(if_none_match, Some(IfNoneMatch::Items(entities))); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -173,6 +173,47 @@ macro_rules! header { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |     // List header, one or more items with "*" option | ||||||
|  |     ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => { | ||||||
|  |         $(#[$a])* | ||||||
|  |         #[derive(Clone, Debug, PartialEq)] | ||||||
|  |         pub enum $id { | ||||||
|  |             /// Any value is a match | ||||||
|  |             Any, | ||||||
|  |             /// Only the listed items are a match | ||||||
|  |             Items(Vec<$item>), | ||||||
|  |         } | ||||||
|  |         impl $crate::header::Header for $id { | ||||||
|  |             fn header_name() -> &'static str { | ||||||
|  |                 $n | ||||||
|  |             } | ||||||
|  |             fn parse_header(raw: &[Vec<u8>]) -> Option<Self> { | ||||||
|  |                 // FIXME: Return None if no item is in $id::Only | ||||||
|  |                 if raw.len() == 1 { | ||||||
|  |                     if raw[0] == b"*" { | ||||||
|  |                         return Some($id::Any) | ||||||
|  |                     } else if raw[0] == b"" { | ||||||
|  |                         return None | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 $crate::header::parsing::from_comma_delimited(raw).map(|vec| $id::Items(vec)) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         impl $crate::header::HeaderFormat for $id { | ||||||
|  |             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||||
|  |                 match *self { | ||||||
|  |                     $id::Any => write!(f, "*"), | ||||||
|  |                     $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(f, &fields[..]) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         impl ::std::fmt::Display for $id { | ||||||
|  |             fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||||
|  |                 use $crate::header::HeaderFormat; | ||||||
|  |                 self.fmt_header(f) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| mod access_control; | mod access_control; | ||||||
|   | |||||||
| @@ -1,9 +1,23 @@ | |||||||
| use header::{Header, HeaderFormat}; |  | ||||||
| use std::fmt::{self}; |  | ||||||
| use header::parsing::{from_comma_delimited, fmt_comma_delimited, from_one_raw_str}; |  | ||||||
| use unicase::UniCase; | use unicase::UniCase; | ||||||
|  |  | ||||||
| /// The `Allow` header. | header! { | ||||||
|  |     #[doc="`Vary` header, defined in [RFC7231](https://tools.ietf.org/html/rfc7231#section-7.1.4)"] | ||||||
|  |     #[doc=""] | ||||||
|  |     #[doc="The \"Vary\" header field in a response describes what parts of a"] | ||||||
|  |     #[doc="request message, aside from the method, Host header field, and"] | ||||||
|  |     #[doc="request target, might influence the origin server's process for"] | ||||||
|  |     #[doc="selecting and representing this response.  The value consists of"] | ||||||
|  |     #[doc="either a single asterisk (\"*\") or a list of header field names"] | ||||||
|  |     #[doc="(case-insensitive)."] | ||||||
|  |     #[doc=""] | ||||||
|  |     #[doc="# ABNF"] | ||||||
|  |     #[doc="```plain"] | ||||||
|  |     #[doc="Vary = \"*\" / 1#field-name"] | ||||||
|  |     #[doc="```"] | ||||||
|  |     (Vary, "Vary") => {Any / (UniCase<String>)+} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*/// The `Allow` header. | ||||||
| /// See also https://tools.ietf.org/html/rfc7231#section-7.1.4 | /// See also https://tools.ietf.org/html/rfc7231#section-7.1.4 | ||||||
|  |  | ||||||
| #[derive(Clone, PartialEq, Debug)] | #[derive(Clone, PartialEq, Debug)] | ||||||
| @@ -38,7 +52,7 @@ impl HeaderFormat for Vary { | |||||||
|             Vary::Headers(ref fields) => { fmt_comma_delimited(fmt, &fields[..]) } |             Vary::Headers(ref fields) => { fmt_comma_delimited(fmt, &fields[..]) } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | }*/ | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
| @@ -53,7 +67,7 @@ mod tests { | |||||||
|         assert_eq!(vary, Some(Vary::Any)); |         assert_eq!(vary, Some(Vary::Any)); | ||||||
|  |  | ||||||
|         vary = Header::parse_header([b"etag,cookie,allow".to_vec()].as_ref()); |         vary = Header::parse_header([b"etag,cookie,allow".to_vec()].as_ref()); | ||||||
|         assert_eq!(vary, Some(Vary::Headers(vec!["eTag".parse().unwrap(), |         assert_eq!(vary, Some(Vary::Items(vec!["eTag".parse().unwrap(), | ||||||
|                                                 "cookIE".parse().unwrap(), |                                                 "cookIE".parse().unwrap(), | ||||||
|                                                 "AlLOw".parse().unwrap(),]))); |                                                 "AlLOw".parse().unwrap(),]))); | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user