headers_ext/common/
content_type.rs

1use std::fmt;
2
3use mime::{self, Mime};
4
5/// `Content-Type` header, defined in
6/// [RFC7231](http://tools.ietf.org/html/rfc7231#section-3.1.1.5)
7///
8/// The `Content-Type` header field indicates the media type of the
9/// associated representation: either the representation enclosed in the
10/// message payload or the selected representation, as determined by the
11/// message semantics.  The indicated media type defines both the data
12/// format and how that data is intended to be processed by a recipient,
13/// within the scope of the received message semantics, after any content
14/// codings indicated by Content-Encoding are decoded.
15///
16/// Although the `mime` crate allows the mime options to be any slice, this crate
17/// forces the use of Vec. This is to make sure the same header can't have more than 1 type. If
18/// this is an issue, it's possible to implement `Header` on a custom struct.
19///
20/// # ABNF
21///
22/// ```text
23/// Content-Type = media-type
24/// ```
25///
26/// # Example values
27///
28/// * `text/html; charset=utf-8`
29/// * `application/json`
30///
31/// # Examples
32///
33/// ```
34/// # extern crate headers_ext as headers;
35/// use headers::ContentType;
36///
37/// let ct = ContentType::json();
38/// ```
39#[derive(Clone, Debug, PartialEq)]
40pub struct ContentType(Mime);
41
42impl ContentType {
43    /// A constructor  to easily create a `Content-Type: application/json` header.
44    #[inline]
45    pub fn json() -> ContentType {
46        ContentType(mime::APPLICATION_JSON)
47    }
48
49    /// A constructor  to easily create a `Content-Type: text/plain` header.
50    #[inline]
51    pub fn text() -> ContentType {
52        ContentType(mime::TEXT_PLAIN)
53    }
54
55    /// A constructor  to easily create a `Content-Type: text/plain; charset=utf-8` header.
56    #[inline]
57    pub fn text_utf8() -> ContentType {
58        ContentType(mime::TEXT_PLAIN_UTF_8)
59    }
60
61    /// A constructor  to easily create a `Content-Type: text/html` header.
62    #[inline]
63    pub fn html() -> ContentType {
64        ContentType(mime::TEXT_HTML)
65    }
66
67    /// A constructor  to easily create a `Content-Type: text/xml` header.
68    #[inline]
69    pub fn xml() -> ContentType {
70        ContentType(mime::TEXT_XML)
71    }
72
73    /// A constructor  to easily create a `Content-Type: application/www-form-url-encoded` header.
74    #[inline]
75    pub fn form_url_encoded() -> ContentType {
76        ContentType(mime::APPLICATION_WWW_FORM_URLENCODED)
77    }
78    /// A constructor  to easily create a `Content-Type: image/jpeg` header.
79    #[inline]
80    pub fn jpeg() -> ContentType {
81        ContentType(mime::IMAGE_JPEG)
82    }
83
84    /// A constructor  to easily create a `Content-Type: image/png` header.
85    #[inline]
86    pub fn png() -> ContentType {
87        ContentType(mime::IMAGE_PNG)
88    }
89
90    /// A constructor  to easily create a `Content-Type: application/octet-stream` header.
91    #[inline]
92    pub fn octet_stream() -> ContentType {
93        ContentType(mime::APPLICATION_OCTET_STREAM)
94    }
95}
96
97impl ::Header for ContentType {
98    const NAME: &'static ::HeaderName = &::http::header::CONTENT_TYPE;
99
100    fn decode<'i, I: Iterator<Item = &'i ::HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
101        values
102            .next()
103            .and_then(|v| v.to_str().ok()?.parse().ok())
104            .map(ContentType)
105            .ok_or_else(::Error::invalid)
106    }
107
108    fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
109        let value = self
110            .0
111            .as_ref()
112            .parse()
113            .expect("Mime is always a valid HeaderValue");
114        values.extend(::std::iter::once(value));
115    }
116}
117
118impl From<mime::Mime> for ContentType {
119    fn from(m: mime::Mime) -> ContentType {
120        ContentType(m)
121    }
122}
123
124impl From<ContentType> for mime::Mime {
125    fn from(ct: ContentType) -> mime::Mime {
126        ct.0
127    }
128}
129
130impl fmt::Display for ContentType {
131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132        fmt::Display::fmt(&self.0, f)
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::ContentType;
139    use super::super::test_decode;
140
141    #[test]
142    fn json() {
143        assert_eq!(
144            test_decode::<ContentType>(&["application/json"]),
145            Some(ContentType::json()),
146        );
147    }
148}
149//bench_header!(bench, ContentType, { vec![b"application/json".to_vec()] });