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