cogo_http/header/common/
mod.rs

1//! A Collection of Header implementations for common HTTP Headers.
2//!
3//! ## Mime
4//!
5//! Several header fields use MIME values for their contents. Keeping with the
6//! strongly-typed theme, the [mime](http://seanmonstar.github.io/mime.rs) crate
7//! is used, such as `ContentType(pub Mime)`.
8
9pub use self::accept::Accept;
10pub use self::access_control_allow_credentials::AccessControlAllowCredentials;
11pub use self::access_control_allow_headers::AccessControlAllowHeaders;
12pub use self::access_control_allow_methods::AccessControlAllowMethods;
13pub use self::access_control_allow_origin::AccessControlAllowOrigin;
14pub use self::access_control_expose_headers::AccessControlExposeHeaders;
15pub use self::access_control_max_age::AccessControlMaxAge;
16pub use self::access_control_request_headers::AccessControlRequestHeaders;
17pub use self::access_control_request_method::AccessControlRequestMethod;
18pub use self::accept_charset::AcceptCharset;
19pub use self::accept_encoding::AcceptEncoding;
20pub use self::accept_language::AcceptLanguage;
21pub use self::accept_ranges::{AcceptRanges, RangeUnit};
22pub use self::allow::Allow;
23pub use self::authorization::{Authorization, Scheme, Basic, Bearer};
24pub use self::cache_control::{CacheControl, CacheDirective};
25pub use self::connection::{Connection, ConnectionOption};
26pub use self::content_disposition::{ContentDisposition, DispositionType, DispositionParam};
27pub use self::content_length::ContentLength;
28pub use self::content_encoding::ContentEncoding;
29pub use self::content_language::ContentLanguage;
30pub use self::content_range::{ContentRange, ContentRangeSpec};
31pub use self::content_type::ContentType;
32pub use self::cookie::Cookie;
33pub use self::date::Date;
34pub use self::etag::ETag;
35pub use self::expect::Expect;
36pub use self::expires::Expires;
37pub use self::from::From;
38pub use self::host::Host;
39pub use self::if_match::IfMatch;
40pub use self::if_modified_since::IfModifiedSince;
41pub use self::if_none_match::IfNoneMatch;
42pub use self::if_unmodified_since::IfUnmodifiedSince;
43pub use self::if_range::IfRange;
44pub use self::last_modified::LastModified;
45pub use self::location::Location;
46pub use self::origin::Origin;
47pub use self::pragma::Pragma;
48pub use self::prefer::{Prefer, Preference};
49pub use self::preference_applied::PreferenceApplied;
50pub use self::range::{Range, ByteRangeSpec};
51pub use self::referer::Referer;
52pub use self::referrer_policy::ReferrerPolicy;
53pub use self::server::Server;
54pub use self::set_cookie::SetCookie;
55pub use self::strict_transport_security::StrictTransportSecurity;
56pub use self::transfer_encoding::TransferEncoding;
57pub use self::upgrade::{Upgrade, Protocol, ProtocolName};
58pub use self::user_agent::UserAgent;
59pub use self::vary::Vary;
60pub use self::link::{Link, LinkValue, RelationType, MediaDesc};
61
62#[doc(hidden)]
63#[macro_export]
64macro_rules! bench_header(
65    ($name:ident, $ty:ty, $value:expr) => {
66        #[cfg(test)]
67        #[cfg(feature = "nightly")]
68        #[allow(deprecated)]
69        mod $name {
70            use test::Bencher;
71            use super::*;
72
73            use crate::header::{Header, HeaderFormatter};
74
75            #[bench]
76            fn bench_parse(b: &mut Bencher) {
77                let val = $value;
78                b.iter(|| {
79                    let _: $ty = Header::parse_header(&val[..]).unwrap();
80                });
81            }
82
83            #[bench]
84            fn bench_format(b: &mut Bencher) {
85                let val: $ty = Header::parse_header(&$value[..]).unwrap();
86                let fmt = HeaderFormatter(&val);
87                b.iter(|| {
88                    format!("{}", fmt);
89                });
90            }
91        }
92    }
93);
94
95#[doc(hidden)]
96#[macro_export]
97macro_rules! __hyper__deref {
98    ($from:ty => $to:ty) => {
99        impl std::ops::Deref for $from {
100            type Target = $to;
101
102            fn deref(&self) -> &$to {
103                &self.0
104            }
105        }
106
107        impl std::ops::DerefMut for $from {
108            fn deref_mut(&mut self) -> &mut $to {
109                &mut self.0
110            }
111        }
112    }
113}
114
115#[doc(hidden)]
116#[macro_export]
117macro_rules! __hyper__tm {
118    ($id:ident, $tm:ident{$($tf:item)*}) => {
119        #[allow(unused_imports)]
120        #[cfg(test)]
121        mod $tm{
122            use std::str;
123            use $crate::header::*;
124            use $crate::mime::*;
125            use $crate::language_tags::*;
126            use $crate::method::Method;
127            use super::$id as HeaderField;
128            $($tf)*
129        }
130
131    }
132}
133
134#[doc(hidden)]
135#[macro_export]
136macro_rules! test_header {
137    ($id:ident, $raw:expr) => {
138        #[test]
139        fn $id() {
140            #[allow(unused_imports)]
141            use std::ascii::AsciiExt;
142            let raw = $raw;
143            let a: Vec<Vec<u8>> = raw.iter().map(|x| x.to_vec()).collect();
144            let value = HeaderField::parse_header(&a[..]);
145            let result = format!("{}", value.unwrap());
146            let expected = String::from_utf8(raw[0].to_vec()).unwrap();
147            let result_cmp: Vec<String> = result
148                .to_ascii_lowercase()
149                .split(' ')
150                .map(|x| x.to_owned())
151                .collect();
152            let expected_cmp: Vec<String> = expected
153                .to_ascii_lowercase()
154                .split(' ')
155                .map(|x| x.to_owned())
156                .collect();
157            assert_eq!(result_cmp.concat(), expected_cmp.concat());
158        }
159    };
160    ($id:ident, $raw:expr, $typed:expr) => {
161        #[test]
162        fn $id() {
163            let a: Vec<Vec<u8>> = $raw.iter().map(|x| x.to_vec()).collect();
164            let val = HeaderField::parse_header(&a[..]);
165            let typed: Option<HeaderField> = $typed;
166            // Test parsing
167            assert_eq!(val.ok(), typed);
168            // Test formatting
169            if typed.is_some() {
170                let raw = &($raw)[..];
171                let mut iter = raw.iter().map(|b|str::from_utf8(&b[..]).unwrap());
172                let mut joined = String::new();
173                joined.push_str(iter.next().unwrap());
174                for s in iter {
175                    joined.push_str(", ");
176                    joined.push_str(s);
177                }
178                assert_eq!(format!("{}", typed.unwrap()), joined);
179            }
180        }
181    }
182}
183
184#[macro_export]
185macro_rules! header {
186    // $a:meta: Attributes associated with the header item (usually docs)
187    // $id:ident: Identifier of the header
188    // $n:expr: Lowercase name of the header
189    // $nn:expr: Nice name of the header
190
191    // List header, zero or more items
192    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)*) => {
193        $(#[$a])*
194        #[derive(Clone, Debug, PartialEq)]
195        pub struct $id(pub Vec<$item>);
196        __hyper__deref!($id => Vec<$item>);
197        impl $crate::header::Header for $id {
198            fn header_name() -> &'static str {
199                $n
200            }
201            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
202                $crate::header::parsing::from_comma_delimited(raw).map($id)
203            }
204        }
205        impl $crate::header::HeaderFormat for $id {
206            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
207                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
208            }
209        }
210        impl ::std::fmt::Display for $id {
211            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
212                use $crate::header::HeaderFormat;
213                self.fmt_header(f)
214            }
215        }
216    };
217    // List header, one or more items
218    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => {
219        $(#[$a])*
220        #[derive(Clone, Debug, PartialEq)]
221        pub struct $id(pub Vec<$item>);
222        __hyper__deref!($id => Vec<$item>);
223        impl $crate::header::Header for $id {
224            fn header_name() -> &'static str {
225                $n
226            }
227            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
228                $crate::header::parsing::from_comma_delimited(raw).map($id)
229            }
230        }
231        impl $crate::header::HeaderFormat for $id {
232            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
233                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
234            }
235        }
236        impl ::std::fmt::Display for $id {
237            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
238                use $crate::header::HeaderFormat;
239                self.fmt_header(f)
240            }
241        }
242    };
243    // Single value header
244    ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => {
245        $(#[$a])*
246        #[derive(Clone, Debug, PartialEq)]
247        pub struct $id(pub $value);
248        __hyper__deref!($id => $value);
249        impl $crate::header::Header for $id {
250            fn header_name() -> &'static str {
251                $n
252            }
253            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
254                $crate::header::parsing::from_one_raw_str(raw).map($id)
255            }
256        }
257        impl $crate::header::HeaderFormat for $id {
258            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
259                ::std::fmt::Display::fmt(&**self, f)
260            }
261        }
262        impl ::std::fmt::Display for $id {
263            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
264                ::std::fmt::Display::fmt(&**self, f)
265            }
266        }
267    };
268    // List header, one or more items with "*" option
269    ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => {
270        $(#[$a])*
271        #[derive(Clone, Debug, PartialEq)]
272        pub enum $id {
273            /// Any value is a match
274            Any,
275            /// Only the listed items are a match
276            Items(Vec<$item>),
277        }
278        impl $crate::header::Header for $id {
279            fn header_name() -> &'static str {
280                $n
281            }
282            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
283                // FIXME: Return None if no item is in $id::Only
284                if raw.len() == 1 {
285                    if raw[0] == b"*" {
286                        return Ok($id::Any)
287                    }
288                }
289                $crate::header::parsing::from_comma_delimited(raw).map($id::Items)
290            }
291        }
292        impl $crate::header::HeaderFormat for $id {
293            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
294                match *self {
295                    $id::Any => f.write_str("*"),
296                    $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(
297                        f, &fields[..])
298                }
299            }
300        }
301        impl ::std::fmt::Display for $id {
302            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
303                use $crate::header::HeaderFormat;
304                self.fmt_header(f)
305            }
306        }
307    };
308
309    // optional test module
310    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
311        header! {
312            $(#[$a])*
313            ($id, $n) => ($item)*
314        }
315
316        __hyper__tm! { $id, $tm { $($tf)* }}
317    };
318    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
319        header! {
320            $(#[$a])*
321            ($id, $n) => ($item)+
322        }
323
324        __hyper__tm! { $id, $tm { $($tf)* }}
325    };
326    ($(#[$a:meta])*($id:ident, $n:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
327        header! {
328            $(#[$a])*
329            ($id, $n) => [$item]
330        }
331
332        __hyper__tm! { $id, $tm { $($tf)* }}
333    };
334    ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
335        header! {
336            $(#[$a])*
337            ($id, $n) => {Any / ($item)+}
338        }
339
340        __hyper__tm! { $id, $tm { $($tf)* }}
341    };
342}
343
344
345mod accept;
346mod access_control_allow_credentials;
347mod access_control_allow_headers;
348mod access_control_allow_methods;
349mod access_control_allow_origin;
350mod access_control_expose_headers;
351mod access_control_max_age;
352mod access_control_request_headers;
353mod access_control_request_method;
354mod accept_charset;
355mod accept_encoding;
356mod accept_language;
357mod accept_ranges;
358mod allow;
359mod authorization;
360mod cache_control;
361mod cookie;
362mod connection;
363mod content_disposition;
364mod content_encoding;
365mod content_language;
366mod content_length;
367mod content_range;
368mod content_type;
369mod date;
370mod etag;
371mod expect;
372mod expires;
373mod from;
374mod host;
375mod if_match;
376mod if_modified_since;
377mod if_none_match;
378mod if_range;
379mod if_unmodified_since;
380mod last_modified;
381mod location;
382mod origin;
383mod pragma;
384mod prefer;
385mod preference_applied;
386mod range;
387mod referer;
388mod referrer_policy;
389mod server;
390mod set_cookie;
391mod strict_transport_security;
392mod transfer_encoding;
393mod upgrade;
394mod user_agent;
395mod vary;
396mod link;