mco_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! __mco_http__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! __mco_http__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            let raw = $raw;
141            let a: Vec<Vec<u8>> = raw.iter().map(|x| x.to_vec()).collect();
142            let value = HeaderField::parse_header(&a[..]);
143            let result = format!("{}", value.unwrap());
144            let expected = String::from_utf8(raw[0].to_vec()).unwrap();
145            let result_cmp: Vec<String> = result
146                .to_ascii_lowercase()
147                .split(' ')
148                .map(|x| x.to_owned())
149                .collect();
150            let expected_cmp: Vec<String> = expected
151                .to_ascii_lowercase()
152                .split(' ')
153                .map(|x| x.to_owned())
154                .collect();
155            assert_eq!(result_cmp.concat(), expected_cmp.concat());
156        }
157    };
158    ($id:ident, $raw:expr, $typed:expr) => {
159        #[test]
160        fn $id() {
161            let a: Vec<Vec<u8>> = $raw.iter().map(|x| x.to_vec()).collect();
162            let val = HeaderField::parse_header(&a[..]);
163            let typed: Option<HeaderField> = $typed;
164            // Test parsing
165            assert_eq!(val.ok(), typed);
166            // Test formatting
167            if typed.is_some() {
168                let raw = &($raw)[..];
169                let mut iter = raw.iter().map(|b|str::from_utf8(&b[..]).unwrap());
170                let mut joined = String::new();
171                joined.push_str(iter.next().unwrap());
172                for s in iter {
173                    joined.push_str(", ");
174                    joined.push_str(s);
175                }
176                assert_eq!(format!("{}", typed.unwrap()), joined);
177            }
178        }
179    }
180}
181
182#[macro_export]
183macro_rules! header {
184    // $a:meta: Attributes associated with the header item (usually docs)
185    // $id:ident: Identifier of the header
186    // $n:expr: Lowercase name of the header
187    // $nn:expr: Nice name of the header
188
189    // List header, zero or more items
190    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)*) => {
191        $(#[$a])*
192        #[derive(Clone, Debug, PartialEq)]
193        pub struct $id(pub Vec<$item>);
194        __mco_http__deref!($id => Vec<$item>);
195        impl $crate::header::Header for $id {
196            fn header_name() -> &'static str {
197                $n
198            }
199            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
200                $crate::header::parsing::from_comma_delimited(raw).map($id)
201            }
202        }
203        impl $crate::header::HeaderFormat for $id {
204            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
205                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
206            }
207        }
208        impl ::std::fmt::Display for $id {
209            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
210                use $crate::header::HeaderFormat;
211                self.fmt_header(f)
212            }
213        }
214    };
215    // List header, one or more items
216    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+) => {
217        $(#[$a])*
218        #[derive(Clone, Debug, PartialEq)]
219        pub struct $id(pub Vec<$item>);
220        __mco_http__deref!($id => Vec<$item>);
221        impl $crate::header::Header for $id {
222            fn header_name() -> &'static str {
223                $n
224            }
225            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
226                $crate::header::parsing::from_comma_delimited(raw).map($id)
227            }
228        }
229        impl $crate::header::HeaderFormat for $id {
230            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
231                $crate::header::parsing::fmt_comma_delimited(f, &self.0[..])
232            }
233        }
234        impl ::std::fmt::Display for $id {
235            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
236                use $crate::header::HeaderFormat;
237                self.fmt_header(f)
238            }
239        }
240    };
241    // Single value header
242    ($(#[$a:meta])*($id:ident, $n:expr) => [$value:ty]) => {
243        $(#[$a])*
244        #[derive(Clone, Debug, PartialEq)]
245        pub struct $id(pub $value);
246        __mco_http__deref!($id => $value);
247        impl $crate::header::Header for $id {
248            fn header_name() -> &'static str {
249                $n
250            }
251            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
252                $crate::header::parsing::from_one_raw_str(raw).map($id)
253            }
254        }
255        impl $crate::header::HeaderFormat for $id {
256            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
257                ::std::fmt::Display::fmt(&**self, f)
258            }
259        }
260        impl ::std::fmt::Display for $id {
261            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
262                ::std::fmt::Display::fmt(&**self, f)
263            }
264        }
265    };
266    // List header, one or more items with "*" option
267    ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+}) => {
268        $(#[$a])*
269        #[derive(Clone, Debug, PartialEq)]
270        pub enum $id {
271            /// Any value is a match
272            Any,
273            /// Only the listed items are a match
274            Items(Vec<$item>),
275        }
276        impl $crate::header::Header for $id {
277            fn header_name() -> &'static str {
278                $n
279            }
280            fn parse_header(raw: &[Vec<u8>]) -> $crate::Result<Self> {
281                // FIXME: Return None if no item is in $id::Only
282                if raw.len() == 1 {
283                    if raw[0] == b"*" {
284                        return Ok($id::Any)
285                    }
286                }
287                $crate::header::parsing::from_comma_delimited(raw).map($id::Items)
288            }
289        }
290        impl $crate::header::HeaderFormat for $id {
291            fn fmt_header(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
292                match *self {
293                    $id::Any => f.write_str("*"),
294                    $id::Items(ref fields) => $crate::header::parsing::fmt_comma_delimited(
295                        f, &fields[..])
296                }
297            }
298        }
299        impl ::std::fmt::Display for $id {
300            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {
301                use $crate::header::HeaderFormat;
302                self.fmt_header(f)
303            }
304        }
305    };
306
307    // optional test module
308    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)* $tm:ident{$($tf:item)*}) => {
309        header! {
310            $(#[$a])*
311            ($id, $n) => ($item)*
312        }
313
314        __mco_http__tm! { $id, $tm { $($tf)* }}
315    };
316    ($(#[$a:meta])*($id:ident, $n:expr) => ($item:ty)+ $tm:ident{$($tf:item)*}) => {
317        header! {
318            $(#[$a])*
319            ($id, $n) => ($item)+
320        }
321
322        __mco_http__tm! { $id, $tm { $($tf)* }}
323    };
324    ($(#[$a:meta])*($id:ident, $n:expr) => [$item:ty] $tm:ident{$($tf:item)*}) => {
325        header! {
326            $(#[$a])*
327            ($id, $n) => [$item]
328        }
329
330        __mco_http__tm! { $id, $tm { $($tf)* }}
331    };
332    ($(#[$a:meta])*($id:ident, $n:expr) => {Any / ($item:ty)+} $tm:ident{$($tf:item)*}) => {
333        header! {
334            $(#[$a])*
335            ($id, $n) => {Any / ($item)+}
336        }
337
338        __mco_http__tm! { $id, $tm { $($tf)* }}
339    };
340}
341
342
343mod accept;
344mod access_control_allow_credentials;
345mod access_control_allow_headers;
346mod access_control_allow_methods;
347mod access_control_allow_origin;
348mod access_control_expose_headers;
349mod access_control_max_age;
350mod access_control_request_headers;
351mod access_control_request_method;
352mod accept_charset;
353mod accept_encoding;
354mod accept_language;
355mod accept_ranges;
356mod allow;
357mod authorization;
358mod cache_control;
359mod cookie;
360mod connection;
361mod content_disposition;
362mod content_encoding;
363mod content_language;
364mod content_length;
365mod content_range;
366mod content_type;
367mod date;
368mod etag;
369mod expect;
370mod expires;
371mod from;
372mod host;
373mod if_match;
374mod if_modified_since;
375mod if_none_match;
376mod if_range;
377mod if_unmodified_since;
378mod last_modified;
379mod location;
380mod origin;
381mod pragma;
382mod prefer;
383mod preference_applied;
384mod range;
385mod referer;
386mod referrer_policy;
387mod server;
388mod set_cookie;
389mod strict_transport_security;
390mod transfer_encoding;
391mod upgrade;
392mod user_agent;
393mod vary;
394mod link;