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