cogo_http/header/common/
accept.rs

1use mime::Mime;
2
3use crate::header::{QualityItem, qitem};
4
5header! {
6    /// `Accept` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.2)
7    ///
8    /// The `Accept` header field can be used by user agents to specify
9    /// response media types that are acceptable.  Accept header fields can
10    /// be used to indicate that the request is specifically limited to a
11    /// small set of desired types, as in the case of a request for an
12    /// in-line image
13    ///
14    /// # ABNF
15    /// ```plain
16    /// Accept = #( media-range [ accept-params ] )
17    ///
18    /// media-range    = ( "*/*"
19    ///                  / ( type "/" "*" )
20    ///                  / ( type "/" subtype )
21    ///                  ) *( OWS ";" OWS parameter )
22    /// accept-params  = weight *( accept-ext )
23    /// accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ]
24    /// ```
25    ///
26    /// # Example values
27    /// * `audio/*; q=0.2, audio/basic` (`*` value won't parse correctly)
28    /// * `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`
29    ///
30    /// # Examples
31    /// ```
32    /// use cogo_http::header::{Headers, Accept, qitem};
33    /// use cogo_http::mime::{Mime, TopLevel, SubLevel};
34    ///
35    /// let mut headers = Headers::new();
36    ///
37    /// headers.set(
38    ///     Accept(vec![
39    ///         qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
40    ///     ])
41    /// );
42    /// ```
43    /// ```
44    /// use cogo_http::header::{Headers, Accept, qitem};
45    /// use cogo_http::mime::{Mime, TopLevel, SubLevel, Attr, Value};
46    ///
47    /// let mut headers = Headers::new();
48    /// headers.set(
49    ///     Accept(vec![
50    ///         qitem(Mime(TopLevel::Application, SubLevel::Json,
51    ///                    vec![(Attr::Charset, Value::Utf8)])),
52    ///     ])
53    /// );
54    /// ```
55    /// ```
56    /// use cogo_http::header::{Headers, Accept, QualityItem, Quality, qitem};
57    /// use cogo_http::mime::{Mime, TopLevel, SubLevel};
58    ///
59    /// let mut headers = Headers::new();
60    ///
61    /// headers.set(
62    ///     Accept(vec![
63    ///         qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
64    ///         qitem(Mime(TopLevel::Application,
65    ///                    SubLevel::Ext("xhtml+xml".to_owned()), vec![])),
66    ///         QualityItem::new(Mime(TopLevel::Application, SubLevel::Xml, vec![]),
67    ///                          Quality(900)),
68    ///                          qitem(Mime(TopLevel::Image,
69    ///                                     SubLevel::Ext("webp".to_owned()), vec![])),
70    ///                          QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]),
71    ///                                           Quality(800))
72    ///     ])
73    /// );
74    /// ```
75    ///
76    /// # Notes
77    /// * Using always Mime types to represent `media-range` differs from the ABNF.
78    /// * **FIXME**: `accept-ext` is not supported.
79    (Accept, "Accept") => (QualityItem<Mime>)+
80
81    test_accept {
82        // Tests from the RFC
83        // FIXME: Test fails, first value containing a "*" fails to parse
84        // test_header!(
85        //    test1,
86        //    vec![b"audio/*; q=0.2, audio/basic"],
87        //    Some(HeaderField(vec![
88        //        QualityItem::new(Mime(TopLevel::Audio, SubLevel::Star, vec![]), Quality(200)),
89        //        qitem(Mime(TopLevel::Audio, SubLevel::Ext("basic".to_owned()), vec![])),
90        //        ])));
91        test_header!(
92            test2,
93            vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
94            Some(HeaderField(vec![
95                QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), Quality(500)),
96                qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
97                QualityItem::new(
98                    Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_owned()), vec![]),
99                    Quality(800)),
100                qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_owned()), vec![])),
101                ])));
102        // Custom tests
103        test_header!(
104            test3,
105            vec![b"text/plain; charset=utf-8"],
106            Some(Accept(vec![
107                qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])),
108                ])));
109        test_header!(
110            test4,
111            vec![b"text/plain; charset=utf-8; q=0.5"],
112            Some(Accept(vec![
113                QualityItem::new(Mime(TopLevel::Text,
114                    SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]),
115                    Quality(500)),
116            ])));
117    }
118}
119
120impl Accept {
121    /// A constructor to easily create `Accept: */*`.
122    pub fn star() -> Accept {
123        Accept(vec![qitem(mime!(Star/Star))])
124    }
125
126    /// A constructor to easily create `Accept: application/json`.
127    pub fn json() -> Accept {
128        Accept(vec![qitem(mime!(Application/Json))])
129    }
130
131    /// A constructor to easily create `Accept: text/*`.
132    pub fn text() -> Accept {
133        Accept(vec![qitem(mime!(Text/Star))])
134    }
135
136    /// A constructor to easily create `Accept: image/*`.
137    pub fn image() -> Accept {
138        Accept(vec![qitem(mime!(Image/Star))])
139    }
140}
141
142
143bench_header!(bench, Accept, { vec![b"text/plain; q=0.5, text/html".to_vec()] });