Merge pull request #419 from pyfisch/refactorheaders1
refactor(headers): Introduce header!() macro, improve documentation
This commit is contained in:
		| @@ -2,39 +2,39 @@ use mime::Mime; | ||||
|  | ||||
| use header::QualityItem; | ||||
|  | ||||
| /// The `Accept` header. | ||||
| /// | ||||
| /// The `Accept` header is used to tell a server which content-types the client | ||||
| /// is capable of using. It can be a comma-separated list of `Mime`s, and the | ||||
| /// priority can be indicated with a `q` parameter. | ||||
| /// | ||||
| /// Example: | ||||
| /// | ||||
| /// ``` | ||||
| /// # use hyper::header::Headers; | ||||
| /// # use hyper::header::Accept; | ||||
| /// # use hyper::header::qitem; | ||||
| /// use hyper::mime::Mime; | ||||
| /// use hyper::mime::TopLevel::Text; | ||||
| /// use hyper::mime::SubLevel::{Html, Xml}; | ||||
| /// # let mut headers = Headers::new(); | ||||
| /// headers.set(Accept(vec![ | ||||
| ///     qitem(Mime(Text, Html, vec![])), | ||||
| ///     qitem(Mime(Text, Xml, vec![])) ])); | ||||
| /// ``` | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct Accept(pub Vec<QualityItem<Mime>>); | ||||
|  | ||||
| impl_list_header!(Accept, | ||||
|                   "Accept", | ||||
|                   Vec<QualityItem<Mime>>); | ||||
| header! { | ||||
|     #[doc="`Accept` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Accept` header field can be used by user agents to specify"] | ||||
|     #[doc="response media types that are acceptable.  Accept header fields can"] | ||||
|     #[doc="be used to indicate that the request is specifically limited to a"] | ||||
|     #[doc="small set of desired types, as in the case of a request for an"] | ||||
|     #[doc="in-line image"] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Accept = #( media-range [ accept-params ] )"] | ||||
|     #[doc=""] | ||||
|     #[doc="media-range    = ( \"*/*\""] | ||||
|     #[doc="                 / ( type \"/\" \"*\" )"] | ||||
|     #[doc="                 / ( type \"/\" subtype )"] | ||||
|     #[doc="                 ) *( OWS \";\" OWS parameter )"] | ||||
|     #[doc="accept-params  = weight *( accept-ext )"] | ||||
|     #[doc="accept-ext = OWS \";\" OWS token [ \"=\" ( token / quoted-string ) ]"] | ||||
|     #[doc="```"] | ||||
|     #[doc=""] | ||||
|     #[doc="# Notes"] | ||||
|     #[doc="* Using always Mime types to represent `media-range` differs from the ABNF."] | ||||
|     #[doc="* **FIXME**: `accept-ext` is not supported."] | ||||
|     (Accept, "Accept") => (QualityItem<Mime>)+ | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use mime::*; | ||||
|  | ||||
|     use header::{Header, Quality, QualityItem, qitem}; | ||||
|      | ||||
|  | ||||
|     use super::Accept; | ||||
|  | ||||
|     #[test] | ||||
|   | ||||
| @@ -1,15 +1,22 @@ | ||||
| use header::{Charset, QualityItem}; | ||||
|  | ||||
| /// The `Accept-Charset` header | ||||
| /// | ||||
| /// The `Accept-Charset` header can be used by clients to indicate what | ||||
| /// response charsets they accept. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct AcceptCharset(pub Vec<QualityItem<Charset>>); | ||||
|  | ||||
| impl_list_header!(AcceptCharset, | ||||
|                   "Accept-Charset", | ||||
|                   Vec<QualityItem<Charset>>); | ||||
| header! { | ||||
|     #[doc="`Accept-Charset` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.3)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Accept-Charset` header field can be sent by a user agent to"] | ||||
|     #[doc="indicate what charsets are acceptable in textual response content."] | ||||
|     #[doc="This field allows user agents capable of understanding more"] | ||||
|     #[doc="comprehensive or special-purpose charsets to signal that capability"] | ||||
|     #[doc="to an origin server that is capable of representing information in"] | ||||
|     #[doc="those charsets."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Accept-Charset = 1#( ( charset / \"*\" ) [ weight ] )"] | ||||
|     #[doc="```"] | ||||
|     (AcceptCharset, "Accept-Charset") => (QualityItem<Charset>)+ | ||||
| } | ||||
|  | ||||
|  | ||||
| #[test] | ||||
|   | ||||
| @@ -1,15 +1,22 @@ | ||||
| use header::{Encoding, QualityItem}; | ||||
|  | ||||
| /// The `Accept-Encoding` header | ||||
| /// | ||||
| /// The `Accept-Encoding` header can be used by clients to indicate what | ||||
| /// response encodings they accept. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct AcceptEncoding(pub Vec<QualityItem<Encoding>>); | ||||
|  | ||||
| impl_list_header!(AcceptEncoding, | ||||
|                   "Accept-Encoding", | ||||
|                   Vec<QualityItem<Encoding>>); | ||||
| header! { | ||||
|     #[doc="`Accept-Encoding` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.4)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Accept-Encoding` header field can be used by user agents to"] | ||||
|     #[doc="indicate what response content-codings are"] | ||||
|     #[doc="acceptable in the response.  An  `identity` token is used as a synonym"] | ||||
|     #[doc="for \"no encoding\" in order to communicate when no encoding is"] | ||||
|     #[doc="preferred."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Accept-Encoding  = #( codings [ weight ] )"] | ||||
|     #[doc="codings          = content-coding / \"identity\" / \"*\""] | ||||
|     #[doc="```"] | ||||
|     (AcceptEncoding, "Accept-Encoding") => (QualityItem<Encoding>)* | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|   | ||||
| @@ -35,16 +35,21 @@ impl fmt::Display for Language { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// The `Accept-Language` header | ||||
| /// | ||||
| /// The `Accept-Language` header can be used by clients to indicate what | ||||
| /// response languages they accept. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct AcceptLanguage(pub Vec<QualityItem<Language>>); | ||||
|  | ||||
| impl_list_header!(AcceptLanguage, | ||||
|                   "Accept-Language", | ||||
|                   Vec<QualityItem<Language>>); | ||||
| header! { | ||||
|     #[doc="`Accept-Language` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.5)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Accept-Language` header field can be used by user agents to"] | ||||
|     #[doc="indicate the set of natural languages that are preferred in the"] | ||||
|     #[doc="response."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Accept-Language = 1#( language-range [ weight ] )"] | ||||
|     #[doc="language-range  = <language-range, see [RFC4647], Section 2.1>"] | ||||
|     #[doc="```"] | ||||
|     (AcceptLanguage, "Accept-Language") => (QualityItem<Language>)+ | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|   | ||||
| @@ -1,14 +1,19 @@ | ||||
| use method::Method; | ||||
|  | ||||
| /// The `Allow` header. | ||||
| /// See also https://tools.ietf.org/html/rfc7231#section-7.4.1 | ||||
|  | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct Allow(pub Vec<Method>); | ||||
|  | ||||
| impl_list_header!(Allow, | ||||
|                   "Allow", | ||||
|                   Vec<Method>); | ||||
| header! { | ||||
|     #[doc="`Allow` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.4.1)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Allow` header field lists the set of methods advertised as"] | ||||
|     #[doc="supported by the target resource.  The purpose of this field is"] | ||||
|     #[doc="strictly to inform the recipient of valid request methods associated"] | ||||
|     #[doc="with the resource."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Allow = #method"] | ||||
|     #[doc="```"] | ||||
|     (Allow, "Allow") => (Method)* | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|   | ||||
| @@ -1,19 +1,23 @@ | ||||
| use header::Encoding; | ||||
|  | ||||
| /// The `Content-Encoding` header. | ||||
| /// | ||||
| /// This header describes the encoding of the message body. It can be | ||||
| /// comma-separated, including multiple encodings. | ||||
| /// | ||||
| /// ```notrust | ||||
| /// Content-Encoding: gzip | ||||
| /// ``` | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct ContentEncoding(pub Vec<Encoding>); | ||||
|  | ||||
| impl_list_header!(ContentEncoding, | ||||
|                   "Content-Encoding", | ||||
|                   Vec<Encoding>); | ||||
| header! { | ||||
|     #[doc="`Content-Encoding` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-3.1.2.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Content-Encoding` header field indicates what content codings"] | ||||
|     #[doc="have been applied to the representation, beyond those inherent in the"] | ||||
|     #[doc="media type, and thus what decoding mechanisms have to be applied in"] | ||||
|     #[doc="order to obtain data in the media type referenced by the Content-Type"] | ||||
|     #[doc="header field.  Content-Encoding is primarily used to allow a"] | ||||
|     #[doc="representation's data to be compressed without losing the identity of"] | ||||
|     #[doc="its underlying media type."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Content-Encoding = 1#content-coding"] | ||||
|     #[doc="```"] | ||||
|     (ContentEncoding, "ContentEncoding") => (Encoding)+ | ||||
| } | ||||
|  | ||||
| bench_header!(single, ContentEncoding, { vec![b"gzip".to_vec()] }); | ||||
| bench_header!(multiple, ContentEncoding, { vec![b"gzip, deflate".to_vec()] }); | ||||
|   | ||||
| @@ -1,11 +1,21 @@ | ||||
| /// The `Content-Length` header. | ||||
| /// | ||||
| /// Simply a wrapper around a `u64`. | ||||
| #[derive(Copy, Clone, PartialEq, Debug)] | ||||
| pub struct ContentLength(pub u64); | ||||
|  | ||||
| impl_header!(ContentLength, | ||||
|              "Content-Length", | ||||
|              u64); | ||||
| header! { | ||||
|     #[doc="`Content-Length` header, defined in"] | ||||
|     #[doc="[RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="When a message does not have a `Transfer-Encoding` header field, a"] | ||||
|     #[doc="Content-Length header field can provide the anticipated size, as a"] | ||||
|     #[doc="decimal number of octets, for a potential payload body.  For messages"] | ||||
|     #[doc="that do include a payload body, the Content-Length field-value"] | ||||
|     #[doc="provides the framing information necessary for determining where the"] | ||||
|     #[doc="body (and message) ends.  For messages that do not include a payload"] | ||||
|     #[doc="body, the Content-Length indicates the size of the selected"] | ||||
|     #[doc="representation."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Content-Length = 1*DIGIT"] | ||||
|     #[doc="```"] | ||||
|     (ContentLength, "Content-Length") => [u64] | ||||
| } | ||||
|  | ||||
| bench_header!(bench, ContentLength, { vec![b"42349984".to_vec()] }); | ||||
|   | ||||
| @@ -1,14 +1,22 @@ | ||||
| use mime::Mime; | ||||
|  | ||||
| /// The `Content-Type` header. | ||||
| /// | ||||
| /// Used to describe the MIME type of message body. Can be used with both | ||||
| /// requests and responses. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct ContentType(pub Mime); | ||||
|  | ||||
| impl_header!(ContentType, | ||||
|              "Content-Type", | ||||
|              Mime); | ||||
| header! { | ||||
|     #[doc="`Content-Type` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-3.1.1.5)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Content-Type` header field indicates the media type of the"] | ||||
|     #[doc="associated representation: either the representation enclosed in the"] | ||||
|     #[doc="message payload or the selected representation, as determined by the"] | ||||
|     #[doc="message semantics.  The indicated media type defines both the data"] | ||||
|     #[doc="format and how that data is intended to be processed by a recipient,"] | ||||
|     #[doc="within the scope of the received message semantics, after any content"] | ||||
|     #[doc="codings indicated by Content-Encoding are decoded."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Content-Type = media-type"] | ||||
|     #[doc="```"] | ||||
|     (ContentType, "Content-Type") => [Mime] | ||||
| } | ||||
|  | ||||
| bench_header!(bench, ContentType, { vec![b"application/json; charset=utf-8".to_vec()] }); | ||||
|   | ||||
| @@ -1,10 +1,17 @@ | ||||
| use header::HttpDate; | ||||
|  | ||||
| /// The `Date` header field. | ||||
| #[derive(Copy, PartialEq, Clone, Debug)] | ||||
| pub struct Date(pub HttpDate); | ||||
|  | ||||
| impl_header!(Date, "Date", HttpDate); | ||||
| header! { | ||||
|     #[doc="`Date` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.1.1.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Date` header field represents the date and time at which the"] | ||||
|     #[doc="message was originated."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Date = HTTP-date"] | ||||
|     #[doc="```"] | ||||
|     (Date, "Date") => [HttpDate] | ||||
| } | ||||
|  | ||||
| bench_header!(imf_fixdate, Date, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); | ||||
| bench_header!(rfc_850, Date, { vec![b"Sunday, 06-Nov-94 08:49:37 GMT".to_vec()] }); | ||||
|   | ||||
| @@ -1,9 +1,21 @@ | ||||
| use header::HttpDate; | ||||
|  | ||||
| /// The `Expires` header field. | ||||
| #[derive(Copy, PartialEq, Clone, Debug)] | ||||
| pub struct Expires(pub HttpDate); | ||||
| impl_header!(Expires, "Expires", HttpDate); | ||||
| header! { | ||||
|     #[doc="`Expires` header, defined in [RFC7234](http://tools.ietf.org/html/rfc7234#section-5.3)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Expires` header field gives the date/time after which the"] | ||||
|     #[doc="response is considered stale."] | ||||
|     #[doc=""] | ||||
|     #[doc="The presence of an Expires field does not imply that the original"] | ||||
|     #[doc="resource will change or cease to exist at, before, or after that"] | ||||
|     #[doc="time."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Expires = HTTP-date"] | ||||
|     #[doc="```"] | ||||
|     (Expires, "Expires") => [HttpDate] | ||||
| } | ||||
|  | ||||
| bench_header!(imf_fixdate, Expires, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); | ||||
| bench_header!(rfc_850, Expires, { vec![b"Sunday, 06-Nov-94 08:49:37 GMT".to_vec()] }); | ||||
|   | ||||
| @@ -1,9 +1,21 @@ | ||||
| use header::HttpDate; | ||||
|  | ||||
| /// The `If-Modified-Since` header field. | ||||
| #[derive(Copy, PartialEq, Clone, Debug)] | ||||
| pub struct IfModifiedSince(pub HttpDate); | ||||
| impl_header!(IfModifiedSince, "If-Modified-Since", HttpDate); | ||||
| header! { | ||||
|     #[doc="`If-Modified-Since` header, defined in"] | ||||
|     #[doc="[RFC7232](http://tools.ietf.org/html/rfc7232#section-3.3)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `If-Modified-Since` header field makes a GET or HEAD request"] | ||||
|     #[doc="method conditional on the selected representation's modification date"] | ||||
|     #[doc="being more recent than the date provided in the field-value."] | ||||
|     #[doc="Transfer of the selected representation's data is avoided if that"] | ||||
|     #[doc="data has not changed."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="If-Unmodified-Since = HTTP-date"] | ||||
|     #[doc="```"] | ||||
|     (IfModifiedSince, "If-Modified-Since") => [HttpDate] | ||||
| } | ||||
|  | ||||
| bench_header!(imf_fixdate, IfModifiedSince, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); | ||||
| bench_header!(rfc_850, IfModifiedSince, { vec![b"Sunday, 06-Nov-94 08:49:37 GMT".to_vec()] }); | ||||
|   | ||||
| @@ -1,10 +1,21 @@ | ||||
| use header::HttpDate; | ||||
|  | ||||
| /// The `If-Unmodified-Since` header field. | ||||
| #[derive(Copy, PartialEq, Clone, Debug)] | ||||
| pub struct IfUnmodifiedSince(pub HttpDate); | ||||
|  | ||||
| impl_header!(IfUnmodifiedSince, "If-Unmodified-Since", HttpDate); | ||||
| header! { | ||||
|     #[doc="`If-Unmodified-Since` header, defined in"] | ||||
|     #[doc="[RFC7232](http://tools.ietf.org/html/rfc7232#section-3.4)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `If-Unmodified-Since` header field makes the request method"] | ||||
|     #[doc="conditional on the selected representation's last modification date"] | ||||
|     #[doc="being earlier than or equal to the date provided in the field-value."] | ||||
|     #[doc="This field accomplishes the same purpose as If-Match for cases where"] | ||||
|     #[doc="the user agent does not have an entity-tag for the representation."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="If-Unmodified-Since = HTTP-date"] | ||||
|     #[doc="```"] | ||||
|     (IfUnmodifiedSince, "If-Unmodified-Since") => [HttpDate] | ||||
| } | ||||
|  | ||||
| bench_header!(imf_fixdate, IfUnmodifiedSince, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); | ||||
| bench_header!(rfc_850, IfUnmodifiedSince, { vec![b"Sunday, 06-Nov-94 08:49:37 GMT".to_vec()] }); | ||||
|   | ||||
| @@ -1,10 +1,19 @@ | ||||
| use header::HttpDate; | ||||
|  | ||||
| /// The `LastModified` header field. | ||||
| #[derive(Copy, PartialEq, Clone, Debug)] | ||||
| pub struct LastModified(pub HttpDate); | ||||
|  | ||||
| impl_header!(LastModified, "Last-Modified", HttpDate); | ||||
| header! { | ||||
|     #[doc="`Last-Modified` header, defined in [RFC7232](http://tools.ietf.org/html/rfc7232#section-2.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Last-Modified` header field in a response provides a timestamp"] | ||||
|     #[doc="indicating the date and time at which the origin server believes the"] | ||||
|     #[doc="selected representation was last modified, as determined at the"] | ||||
|     #[doc="conclusion of handling the request."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Expires = HTTP-date"] | ||||
|     #[doc="```"] | ||||
|     (LastModified, "Last-Modified") => [HttpDate] | ||||
| } | ||||
|  | ||||
| bench_header!(imf_fixdate, LastModified, { vec![b"Sun, 07 Nov 1994 08:48:37 GMT".to_vec()] }); | ||||
| bench_header!(rfc_850, LastModified, { vec![b"Sunday, 06-Nov-94 08:49:37 GMT".to_vec()] }); | ||||
|   | ||||
| @@ -1,19 +1,19 @@ | ||||
| /// The `Location` header. | ||||
| /// | ||||
| /// The Location response-header field is used to redirect the recipient to | ||||
| /// a location other than the Request-URI for completion of the request or identification | ||||
| /// of a new resource. For 201 (Created) responses, the Location is that of the new | ||||
| /// resource which was created by the request. For 3xx responses, the location SHOULD | ||||
| /// indicate the server's preferred URI for automatic redirection to the resource. | ||||
| /// The field value consists of a single absolute URI. | ||||
| /// | ||||
| /// Currently is just a String, but it should probably become a better type, | ||||
| /// like url::Url or something. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct Location(pub String); | ||||
| header! { | ||||
|     #[doc="`Location` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-7.1.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Location` header field is used in some responses to refer to a"] | ||||
|     #[doc="specific resource in relation to the response.  The type of"] | ||||
|     #[doc="relationship is defined by the combination of request method and"] | ||||
|     #[doc="status code semantics."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Location = URI-reference"] | ||||
|     #[doc="```"] | ||||
|     // TODO: Use URL | ||||
|     (Location, "Location") => [String] | ||||
|  | ||||
| impl_header!(Location, | ||||
|              "Location", | ||||
|              String); | ||||
| } | ||||
|  | ||||
| bench_header!(bench, Location, { vec![b"http://foo.com/hello:3000".to_vec()] }); | ||||
|   | ||||
| @@ -89,64 +89,91 @@ macro_rules! deref( | ||||
| ); | ||||
|  | ||||
| #[macro_export] | ||||
| macro_rules! impl_list_header( | ||||
|     ($from:ident, $name:expr, $item:ty) => { | ||||
|         deref!($from => $item); | ||||
| macro_rules! header { | ||||
|     // $a:meta: Attributes associated with the header item (usually docs) | ||||
|     // $id:ident: Identifier of the header | ||||
|     // $n:expr: Lowercase name of the header | ||||
|     // $nn:expr: Nice name of the header | ||||
|  | ||||
|         impl $crate::header::Header for $from { | ||||
|     // List header, zero or more items | ||||
|     ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)*) => { | ||||
|         $(#[$a])* | ||||
|         #[derive(Clone, Debug, PartialEq)] | ||||
|         pub struct $id(pub Vec<$item>); | ||||
|         deref!($id => Vec<$item>); | ||||
|         impl $crate::header::Header for $id { | ||||
|             fn header_name() -> &'static str { | ||||
|                 $name | ||||
|                 $n | ||||
|             } | ||||
|  | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> Option<$from> { | ||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($from) | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> Option<Self> { | ||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         impl $crate::header::HeaderFormat for $from { | ||||
|             fn fmt_header(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 $crate::header::parsing::fmt_comma_delimited(fmt, &self[..]) | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 $crate::header::parsing::fmt_comma_delimited(f, &self.0[..]) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         impl ::std::fmt::Display for $from { | ||||
|         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) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| ); | ||||
|  | ||||
| #[macro_export] | ||||
| macro_rules! impl_header( | ||||
|     ($from:ident, $name:expr, $item:ty) => { | ||||
|         deref!($from => $item); | ||||
|  | ||||
|         impl $crate::header::Header for $from { | ||||
|     }; | ||||
|     // List header, one or more items | ||||
|     ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => { | ||||
|         $(#[$a])* | ||||
|         #[derive(Clone, Debug, PartialEq)] | ||||
|         pub struct $id(pub Vec<$item>); | ||||
|         deref!($id => Vec<$item>); | ||||
|         impl $crate::header::Header for $id { | ||||
|             fn header_name() -> &'static str { | ||||
|                 $name | ||||
|                 $n | ||||
|             } | ||||
|  | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> Option<$from> { | ||||
|                 $crate::header::parsing::from_one_raw_str(raw).map($from) | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> Option<Self> { | ||||
|                 $crate::header::parsing::from_comma_delimited(raw).map($id) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         impl $crate::header::HeaderFormat for $from { | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 $crate::header::parsing::fmt_comma_delimited(f, &self.0[..]) | ||||
|             } | ||||
|         } | ||||
|         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) | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|     // Single value header | ||||
|     ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => { | ||||
|         $(#[$a])* | ||||
|         #[derive(Clone, Debug, PartialEq)] | ||||
|         pub struct $id(pub $value); | ||||
|         deref!($id => $value); | ||||
|         impl $crate::header::Header for $id { | ||||
|             fn header_name() -> &'static str { | ||||
|                 $n | ||||
|             } | ||||
|             fn parse_header(raw: &[Vec<u8>]) -> Option<Self> { | ||||
|                 $crate::header::parsing::from_one_raw_str(raw).map($id) | ||||
|             } | ||||
|         } | ||||
|         impl $crate::header::HeaderFormat for $id { | ||||
|             fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||
|                 ::std::fmt::Display::fmt(&**self, f) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         impl ::std::fmt::Display for $from { | ||||
|         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) | ||||
|                 ::std::fmt::Display::fmt(&**self, f) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| ); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| mod access_control; | ||||
| mod accept; | ||||
|   | ||||
| @@ -1,16 +1,19 @@ | ||||
| /// The `Referer` header. | ||||
| /// | ||||
| /// The Referer header is used by user agents to inform server about | ||||
| /// the page URL user has came from. | ||||
| /// | ||||
| /// See alse [RFC 1945, section 10.13](http://tools.ietf.org/html/rfc1945#section-10.13). | ||||
| /// | ||||
| /// Currently just a string, but maybe better replace it with url::Url or something like it. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct Referer(pub String); | ||||
|  | ||||
| impl_header!(Referer, | ||||
|              "Referer", | ||||
|              String); | ||||
| header! { | ||||
|     #[doc="`Referer` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-5.5.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Referer` [sic] header field allows the user agent to specify a"] | ||||
|     #[doc="URI reference for the resource from which the target URI was obtained"] | ||||
|     #[doc="(i.e., the \"referrer\", though the field name is misspelled).  A user"] | ||||
|     #[doc="agent MUST NOT include the fragment and userinfo components of the"] | ||||
|     #[doc="URI reference, if any, when generating the Referer field value."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Referer = absolute-URI / partial-URI"] | ||||
|     #[doc="```"] | ||||
|     // TODO: Use URL | ||||
|     (Referer, "Referer") => [String] | ||||
| } | ||||
|  | ||||
| bench_header!(bench, Referer, { vec![b"http://foo.com/hello:3000".to_vec()] }); | ||||
|   | ||||
| @@ -1,11 +1,20 @@ | ||||
| /// The `Server` header field. | ||||
| /// | ||||
| /// They can contain any value, so it just wraps a `String`. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct Server(pub String); | ||||
|  | ||||
| impl_header!(Server, | ||||
|              "Server", | ||||
|              String); | ||||
| header! { | ||||
|     #[doc="`Server` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.4.2)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Server` header field contains information about the software"] | ||||
|     #[doc="used by the origin server to handle the request, which is often used"] | ||||
|     #[doc="by clients to help identify the scope of reported interoperability"] | ||||
|     #[doc="problems, to work around or tailor requests to avoid particular"] | ||||
|     #[doc="server limitations, and for analytics regarding server or operating"] | ||||
|     #[doc="system use.  An origin server MAY generate a Server field in its"] | ||||
|     #[doc="responses."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Server = product *( RWS ( product / comment ) )"] | ||||
|     #[doc="```"] | ||||
|     // TODO: Maybe parse as defined in the spec? | ||||
|     (Server, "Server") => [String] | ||||
| } | ||||
|  | ||||
| bench_header!(bench, Server, { vec![b"Some String".to_vec()] }); | ||||
|   | ||||
| @@ -1,24 +1,20 @@ | ||||
| use header::Encoding; | ||||
|  | ||||
| /// The `Transfer-Encoding` header. | ||||
| /// | ||||
| /// This header describes the encoding of the message body. It can be | ||||
| /// comma-separated, including multiple encodings. | ||||
| /// | ||||
| /// ```notrust | ||||
| /// Transfer-Encoding: gzip, chunked | ||||
| /// ``` | ||||
| /// | ||||
| /// According to the spec, if a `Content-Length` header is not included, | ||||
| /// this header should include `chunked` as the last encoding. | ||||
| /// | ||||
| /// The implementation uses a vector of `Encoding` values. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct TransferEncoding(pub Vec<Encoding>); | ||||
|  | ||||
| impl_list_header!(TransferEncoding, | ||||
|                   "Transfer-Encoding", | ||||
|                   Vec<Encoding>); | ||||
| header! { | ||||
|     #[doc="`Transfer-Encoding` header, defined in"] | ||||
|     #[doc="[RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.1)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `Transfer-Encoding` header field lists the transfer coding names"] | ||||
|     #[doc="corresponding to the sequence of transfer codings that have been (or"] | ||||
|     #[doc="will be) applied to the payload body in order to form the message"] | ||||
|     #[doc="body."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="Transfer-Encoding = 1#transfer-coding"] | ||||
|     #[doc="```"] | ||||
|     (TransferEncoding, "Transfer-Encoding") => (Encoding)+ | ||||
| } | ||||
|  | ||||
| bench_header!(normal, TransferEncoding, { vec![b"chunked, gzip".to_vec()] }); | ||||
| bench_header!(ext, TransferEncoding, { vec![b"ext".to_vec()] }); | ||||
|   | ||||
| @@ -1,14 +1,24 @@ | ||||
| /// The `User-Agent` header field. | ||||
| /// | ||||
| /// They can contain any value, so it just wraps a `String`. | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub struct UserAgent(pub String); | ||||
|  | ||||
| impl_header!(UserAgent, | ||||
|              "User-Agent", | ||||
|              String); | ||||
|  | ||||
| bench_header!(bench, UserAgent, { vec![b"cargo bench".to_vec()] }); | ||||
| header! { | ||||
|     #[doc="`User-Agent` header, defined in"] | ||||
|     #[doc="[RFC7231](http://tools.ietf.org/html/rfc7231#section-5.5.3)"] | ||||
|     #[doc=""] | ||||
|     #[doc="The `User-Agent` header field contains information about the user"] | ||||
|     #[doc="agent originating the request, which is often used by servers to help"] | ||||
|     #[doc="identify the scope of reported interoperability problems, to work"] | ||||
|     #[doc="around or tailor responses to avoid particular user agent"] | ||||
|     #[doc="limitations, and for analytics regarding browser or operating system"] | ||||
|     #[doc="use.  A user agent SHOULD send a User-Agent field in each request"] | ||||
|     #[doc="unless specifically configured not to do so."] | ||||
|     #[doc=""] | ||||
|     #[doc="# ABNF"] | ||||
|     #[doc="```plain"] | ||||
|     #[doc="User-Agent = product *( RWS ( product / comment ) )"] | ||||
|     #[doc="product         = token [\"/\" product-version]"] | ||||
|     #[doc="product-version = token"] | ||||
|     #[doc="```"] | ||||
|     // TODO: Maybe write parsing according to the spec? (Split the String) | ||||
|     (UserAgent, "User-Agent") => [String] | ||||
| } | ||||
|  | ||||
| #[test] fn test_format() { | ||||
|     use std::borrow::ToOwned; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user