Skip to content

Commit

Permalink
refactor(headers): Introduce header!() macro, improve documentation
Browse files Browse the repository at this point in the history
The new macro handles single value headers, list headers, and list
headers with at least one item.
It creates the item for the header and contains its documentation. The
new macro allows handling
more header cases in the future, it will also be possible to include
tests inside the macro.

BREAKING CHANGE: Removed impl_header!() and impl_list_header!() macros,
use new header!() macro.
  • Loading branch information
pyfisch committed Apr 2, 2015
1 parent eeba13b commit 262c450
Show file tree
Hide file tree
Showing 19 changed files with 367 additions and 225 deletions.
54 changes: 27 additions & 27 deletions src/header/common/accept.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
27 changes: 17 additions & 10 deletions src/header/common/accept_charset.rs
Original file line number Diff line number Diff line change
@@ -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]
Expand Down
27 changes: 17 additions & 10 deletions src/header/common/accept_encoding.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
25 changes: 15 additions & 10 deletions src/header/common/accept_language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
23 changes: 14 additions & 9 deletions src/header/common/allow.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
32 changes: 18 additions & 14 deletions src/header/common/content_encoding.rs
Original file line number Diff line number Diff line change
@@ -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()] });
28 changes: 19 additions & 9 deletions src/header/common/content_length.rs
Original file line number Diff line number Diff line change
@@ -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()] });
28 changes: 18 additions & 10 deletions src/header/common/content_type.rs
Original file line number Diff line number Diff line change
@@ -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()] });
17 changes: 12 additions & 5 deletions src/header/common/date.rs
Original file line number Diff line number Diff line change
@@ -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()] });
Expand Down
20 changes: 16 additions & 4 deletions src/header/common/expires.rs
Original file line number Diff line number Diff line change
@@ -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()] });
Expand Down
20 changes: 16 additions & 4 deletions src/header/common/if_modified_since.rs
Original file line number Diff line number Diff line change
@@ -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()] });
Expand Down
21 changes: 16 additions & 5 deletions src/header/common/if_unmodified_since.rs
Original file line number Diff line number Diff line change
@@ -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()] });
Expand Down
Loading

0 comments on commit 262c450

Please sign in to comment.