Skip to content

Commit f273224

Browse files
committed
feat(mime): upgrade to mime v0.3
The new mime crate has several benefits: - Faster formatting - Easier to use. Most common mime types are now just constants, like `mime::TEXT_PLAIN`. - Proper suffix support. - Extensible without breaking backwards compatiblity. This means we can always add new constants, but before we couldn't add new variants to the enums. - It's now impossible for a `Mime` to contain invalid tokens. Before, with the `Ext(String)` variants, it was possible to create an illegal mime. Closes #738 BREAKING CHANGE: Most uses of `mime` will likely break. There is no more `mime!` macro, nor a `Mime` constructor, nor `TopLevel` and `SubLevel` enums. Instead, in most cases, a constant exists that can now be used. For less common mime types, they can be created by parsing a string.
1 parent e2ed6f5 commit f273224

File tree

7 files changed

+59
-94
lines changed

7 files changed

+59
-94
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ futures-cpupool = "0.1"
2626
httparse = "1.0"
2727
language-tags = "0.2"
2828
log = "0.3"
29-
mime = "0.2"
29+
mime = "0.3"
3030
time = "0.1"
3131
tokio-core = "0.1.6"
3232
tokio-proto = "0.1"

src/header/common/accept.rs

+35-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use mime::Mime;
1+
use mime::{self, Mime};
22

33
use header::{QualityItem, qitem};
44

@@ -24,94 +24,89 @@ header! {
2424
/// ```
2525
///
2626
/// # Example values
27-
/// * `audio/*; q=0.2, audio/basic` (`*` value won't parse correctly)
27+
/// * `audio/*; q=0.2, audio/basic`
2828
/// * `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`
2929
///
3030
/// # Examples
3131
/// ```
3232
/// use hyper::header::{Headers, Accept, qitem};
33-
/// use hyper::mime::{Mime, TopLevel, SubLevel};
33+
/// use hyper::mime;
3434
///
3535
/// let mut headers = Headers::new();
3636
///
3737
/// headers.set(
3838
/// Accept(vec![
39-
/// qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
39+
/// qitem(mime::TEXT_HTML),
4040
/// ])
4141
/// );
4242
/// ```
4343
/// ```
4444
/// use hyper::header::{Headers, Accept, qitem};
45-
/// use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
45+
/// use hyper::mime;
4646
///
4747
/// let mut headers = Headers::new();
4848
/// headers.set(
4949
/// Accept(vec![
50-
/// qitem(Mime(TopLevel::Application, SubLevel::Json,
51-
/// vec![(Attr::Charset, Value::Utf8)])),
50+
/// qitem(mime::APPLICATION_JSON),
5251
/// ])
5352
/// );
5453
/// ```
5554
/// ```
5655
/// use hyper::header::{Headers, Accept, QualityItem, q, qitem};
57-
/// use hyper::mime::{Mime, TopLevel, SubLevel};
56+
/// use hyper::mime;
5857
///
5958
/// let mut headers = Headers::new();
6059
///
6160
/// headers.set(
6261
/// 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-
/// q(900)),
68-
/// qitem(Mime(TopLevel::Image,
69-
/// SubLevel::Ext("webp".to_owned()), vec![])),
70-
/// QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]),
71-
/// q(800))
62+
/// qitem(mime::TEXT_HTML),
63+
/// qitem("application/xhtml+xml".parse().unwrap()),
64+
/// QualityItem::new(
65+
/// mime::TEXT_XML,
66+
/// q(900)
67+
/// ),
68+
/// qitem("image/webp".parse().unwrap()),
69+
/// QualityItem::new(
70+
/// mime::STAR_STAR,
71+
/// q(800)
72+
/// ),
7273
/// ])
7374
/// );
7475
/// ```
75-
///
76-
/// # Notes
77-
/// * Using always Mime types to represent `media-range` differs from the ABNF.
78-
/// * **FIXME**: `accept-ext` is not supported.
7976
(Accept, "Accept") => (QualityItem<Mime>)+
8077

8178
test_accept {
8279
// 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![]), q(200)),
89-
// qitem(Mime(TopLevel::Audio, SubLevel::Ext("basic".to_owned()), vec![])),
90-
// ])));
80+
test_header!(
81+
test1,
82+
vec![b"audio/*; q=0.2, audio/basic"],
83+
Some(HeaderField(vec![
84+
QualityItem::new("audio/*".parse().unwrap(), q(200)),
85+
qitem("audio/basic".parse().unwrap()),
86+
])));
9187
test_header!(
9288
test2,
9389
vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
9490
Some(HeaderField(vec![
95-
QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), q(500)),
96-
qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
91+
QualityItem::new(TEXT_PLAIN, q(500)),
92+
qitem(TEXT_HTML),
9793
QualityItem::new(
98-
Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_owned()), vec![]),
94+
"text/x-dvi".parse().unwrap(),
9995
q(800)),
100-
qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_owned()), vec![])),
96+
qitem("text/x-c".parse().unwrap()),
10197
])));
10298
// Custom tests
10399
test_header!(
104100
test3,
105101
vec![b"text/plain; charset=utf-8"],
106102
Some(Accept(vec![
107-
qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])),
103+
qitem(TEXT_PLAIN_UTF_8),
108104
])));
109105
test_header!(
110106
test4,
111107
vec![b"text/plain; charset=utf-8; q=0.5"],
112108
Some(Accept(vec![
113-
QualityItem::new(Mime(TopLevel::Text,
114-
SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]),
109+
QualityItem::new(TEXT_PLAIN_UTF_8,
115110
q(500)),
116111
])));
117112

@@ -127,22 +122,22 @@ header! {
127122
impl Accept {
128123
/// A constructor to easily create `Accept: */*`.
129124
pub fn star() -> Accept {
130-
Accept(vec![qitem(mime!(Star/Star))])
125+
Accept(vec![qitem(mime::STAR_STAR)])
131126
}
132127

133128
/// A constructor to easily create `Accept: application/json`.
134129
pub fn json() -> Accept {
135-
Accept(vec![qitem(mime!(Application/Json))])
130+
Accept(vec![qitem(mime::APPLICATION_JSON)])
136131
}
137132

138133
/// A constructor to easily create `Accept: text/*`.
139134
pub fn text() -> Accept {
140-
Accept(vec![qitem(mime!(Text/Star))])
135+
Accept(vec![qitem(mime::TEXT_STAR)])
141136
}
142137

143138
/// A constructor to easily create `Accept: image/*`.
144139
pub fn image() -> Accept {
145-
Accept(vec![qitem(mime!(Image/Star))])
140+
Accept(vec![qitem(mime::IMAGE_STAR)])
146141
}
147142
}
148143

src/header/common/content_type.rs

+15-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use mime::Mime;
1+
use mime::{self, Mime};
22

33
header! {
44
/// `Content-Type` header, defined in
@@ -22,7 +22,8 @@ header! {
2222
/// ```
2323
///
2424
/// # Example values
25-
/// * `text/html; charset=ISO-8859-4`
25+
/// * `text/html; charset=utf-8`
26+
/// * `application/json
2627
///
2728
/// # Examples
2829
/// ```
@@ -36,73 +37,67 @@ header! {
3637
/// ```
3738
/// ```
3839
/// use hyper::header::{Headers, ContentType};
39-
/// use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
40+
/// use hyper::mime;
4041
///
4142
/// let mut headers = Headers::new();
4243
///
4344
/// headers.set(
44-
/// ContentType(Mime(TopLevel::Text, SubLevel::Html,
45-
/// vec![(Attr::Charset, Value::Utf8)]))
45+
/// ContentType(mime::TEXT_HTML)
4646
/// );
4747
/// ```
4848
(ContentType, "Content-Type") => [Mime]
4949

5050
test_content_type {
5151
test_header!(
5252
test1,
53-
// FIXME: Should be b"text/html; charset=ISO-8859-4" but mime crate lowercases
54-
// the whole value so parsing and formatting the value gives a different result
55-
vec![b"text/html; charset=iso-8859-4"],
56-
Some(HeaderField(Mime(
57-
TopLevel::Text,
58-
SubLevel::Html,
59-
vec![(Attr::Charset, Value::Ext("iso-8859-4".to_owned()))]))));
53+
vec![b"text/html"],
54+
Some(HeaderField(TEXT_HTML)));
6055
}
6156
}
6257

6358
impl ContentType {
6459
/// A constructor to easily create a `Content-Type: application/json` header.
6560
#[inline]
6661
pub fn json() -> ContentType {
67-
ContentType(mime!(Application/Json))
62+
ContentType(mime::APPLICATION_JSON)
6863
}
6964

7065
/// A constructor to easily create a `Content-Type: text/plain; charset=utf-8` header.
7166
#[inline]
7267
pub fn plaintext() -> ContentType {
73-
ContentType(mime!(Text/Plain; Charset=Utf8))
68+
ContentType(mime::TEXT_PLAIN_UTF_8)
7469
}
7570

7671
/// A constructor to easily create a `Content-Type: text/html; charset=utf-8` header.
7772
#[inline]
7873
pub fn html() -> ContentType {
79-
ContentType(mime!(Text/Html; Charset=Utf8))
74+
ContentType(mime::TEXT_HTML)
8075
}
8176

8277
/// A constructor to easily create a `Content-Type: application/www-form-url-encoded` header.
8378
#[inline]
8479
pub fn form_url_encoded() -> ContentType {
85-
ContentType(mime!(Application/WwwFormUrlEncoded))
80+
ContentType(mime::APPLICATION_WWW_FORM_URLENCODED)
8681
}
8782
/// A constructor to easily create a `Content-Type: image/jpeg` header.
8883
#[inline]
8984
pub fn jpeg() -> ContentType {
90-
ContentType(mime!(Image/Jpeg))
85+
ContentType(mime::IMAGE_JPEG)
9186
}
9287

9388
/// A constructor to easily create a `Content-Type: image/png` header.
9489
#[inline]
9590
pub fn png() -> ContentType {
96-
ContentType(mime!(Image/Png))
91+
ContentType(mime::IMAGE_PNG)
9792
}
9893

9994
/// A constructor to easily create a `Content-Type: application/octet-stream` header.
10095
#[inline]
10196
pub fn octet_stream() -> ContentType {
102-
ContentType(mime!(Application/OctetStream))
97+
ContentType(mime::APPLICATION_OCTET_STREAM)
10398
}
10499
}
105100

106101
impl Eq for ContentType {}
107102

108-
bench_header!(bench, ContentType, { vec![b"application/json; charset=utf-8".to_vec()] });
103+
bench_header!(bench, ContentType, { vec![b"application/json".to_vec()] });

src/header/common/link.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,7 @@ mod tests {
905905
use http::{ServerTransaction, Http1Transaction};
906906
use bytes::BytesMut;
907907

908-
use mime::Mime;
909-
use mime::TopLevel::Text;
910-
use mime::SubLevel::Plain;
908+
use mime;
911909

912910
#[test]
913911
fn test_link() {
@@ -956,7 +954,7 @@ mod tests {
956954
.push_media_desc(MediaDesc::Screen)
957955
.set_title("previous chapter")
958956
.set_title_star("title* unparsed")
959-
.set_media_type(Mime(Text, Plain, vec![]));
957+
.set_media_type(mime::TEXT_PLAIN);
960958

961959
let link_header = b"<http://example.com/TheBook/chapter2>; \
962960
rel=\"previous\"; anchor=\"../anchor/example/\"; \
@@ -1015,7 +1013,7 @@ mod tests {
10151013
.push_media_desc(MediaDesc::Screen)
10161014
.set_title("previous chapter")
10171015
.set_title_star("title* unparsed")
1018-
.set_media_type(Mime(Text, Plain, vec![]));
1016+
.set_media_type(mime::TEXT_PLAIN);
10191017

10201018
let link = Link::new(vec![link_value]);
10211019

src/header/common/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! ## Mime
44
//!
55
//! 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
6+
//! strongly-typed theme, the [mime](https://docs.rs/mime) crate
77
//! is used, such as `ContentType(pub Mime)`.
88
99
pub use self::accept::Accept;

src/header/mod.rs

+3-26
Original file line numberDiff line numberDiff line change
@@ -696,11 +696,7 @@ impl PartialEq<HeaderName> for str {
696696
#[cfg(test)]
697697
mod tests {
698698
use std::fmt;
699-
use mime::Mime;
700-
use mime::TopLevel::Text;
701-
use mime::SubLevel::Plain;
702-
use super::{Headers, Header, Raw, ContentLength, ContentType,
703-
Accept, Host, qitem, SetCookie};
699+
use super::{Headers, Header, Raw, ContentLength, ContentType, Host, SetCookie};
704700

705701
#[cfg(feature = "nightly")]
706702
use test::Bencher;
@@ -723,25 +719,6 @@ mod tests {
723719
assert_eq!(headers.get(), Some(&ContentLength(10)));
724720
}
725721

726-
#[test]
727-
fn test_content_type() {
728-
let content_type = Header::parse_header(&b"text/plain".as_ref().into());
729-
assert_eq!(content_type.ok(), Some(ContentType(Mime(Text, Plain, vec![]))));
730-
}
731-
732-
#[test]
733-
fn test_accept() {
734-
let text_plain = qitem(Mime(Text, Plain, vec![]));
735-
let application_vendor = "application/vnd.github.v3.full+json; q=0.5".parse().unwrap();
736-
737-
let accept = Header::parse_header(&b"text/plain".as_ref().into());
738-
assert_eq!(accept.ok(), Some(Accept(vec![text_plain.clone()])));
739-
740-
let bytevec = b"application/vnd.github.v3.full+json; q=0.5, text/plain".as_ref().into();
741-
let accept = Header::parse_header(&bytevec);
742-
assert_eq!(accept.ok(), Some(Accept(vec![application_vendor, text_plain])));
743-
}
744-
745722
#[derive(Clone, PartialEq, Debug)]
746723
struct CrazyLength(Option<bool>, usize);
747724

@@ -882,7 +859,7 @@ mod tests {
882859
let mut headers = Headers::new();
883860
headers.set(ContentLength(10));
884861
assert_eq!(headers.len(), 1);
885-
headers.set(ContentType(Mime(Text, Plain, vec![])));
862+
headers.set(ContentType::json());
886863
assert_eq!(headers.len(), 2);
887864
// Redundant, should not increase count.
888865
headers.set(ContentLength(20));
@@ -893,7 +870,7 @@ mod tests {
893870
fn test_clear() {
894871
let mut headers = Headers::new();
895872
headers.set(ContentLength(10));
896-
headers.set(ContentType(Mime(Text, Plain, vec![])));
873+
headers.set(ContentType::json());
897874
assert_eq!(headers.len(), 2);
898875
headers.clear();
899876
assert_eq!(headers.len(), 0);

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ extern crate futures_cpupool;
2020
extern crate httparse;
2121
extern crate language_tags;
2222
#[macro_use] extern crate log;
23-
#[macro_use] pub extern crate mime;
23+
pub extern crate mime;
2424
extern crate base64;
2525
extern crate time;
2626
extern crate tokio_core as tokio;

0 commit comments

Comments
 (0)