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()] });