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.
This commit is contained in:
@@ -26,7 +26,7 @@ futures-cpupool = "0.1"
|
||||
httparse = "1.0"
|
||||
language-tags = "0.2"
|
||||
log = "0.3"
|
||||
mime = "0.2"
|
||||
mime = "0.3"
|
||||
time = "0.1"
|
||||
tokio-core = "0.1.6"
|
||||
tokio-proto = "0.1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use mime::Mime;
|
||||
use mime::{self, Mime};
|
||||
|
||||
use header::{QualityItem, qitem};
|
||||
|
||||
@@ -24,94 +24,89 @@ header! {
|
||||
/// ```
|
||||
///
|
||||
/// # Example values
|
||||
/// * `audio/*; q=0.2, audio/basic` (`*` value won't parse correctly)
|
||||
/// * `audio/*; q=0.2, audio/basic`
|
||||
/// * `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, Accept, qitem};
|
||||
/// use hyper::mime::{Mime, TopLevel, SubLevel};
|
||||
/// use hyper::mime;
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
///
|
||||
/// headers.set(
|
||||
/// Accept(vec![
|
||||
/// qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
|
||||
/// qitem(mime::TEXT_HTML),
|
||||
/// ])
|
||||
/// );
|
||||
/// ```
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, Accept, qitem};
|
||||
/// use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
|
||||
/// use hyper::mime;
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
/// headers.set(
|
||||
/// Accept(vec![
|
||||
/// qitem(Mime(TopLevel::Application, SubLevel::Json,
|
||||
/// vec![(Attr::Charset, Value::Utf8)])),
|
||||
/// qitem(mime::APPLICATION_JSON),
|
||||
/// ])
|
||||
/// );
|
||||
/// ```
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, Accept, QualityItem, q, qitem};
|
||||
/// use hyper::mime::{Mime, TopLevel, SubLevel};
|
||||
/// use hyper::mime;
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
///
|
||||
/// headers.set(
|
||||
/// Accept(vec![
|
||||
/// qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
|
||||
/// qitem(Mime(TopLevel::Application,
|
||||
/// SubLevel::Ext("xhtml+xml".to_owned()), vec![])),
|
||||
/// QualityItem::new(Mime(TopLevel::Application, SubLevel::Xml, vec![]),
|
||||
/// q(900)),
|
||||
/// qitem(Mime(TopLevel::Image,
|
||||
/// SubLevel::Ext("webp".to_owned()), vec![])),
|
||||
/// QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]),
|
||||
/// q(800))
|
||||
/// qitem(mime::TEXT_HTML),
|
||||
/// qitem("application/xhtml+xml".parse().unwrap()),
|
||||
/// QualityItem::new(
|
||||
/// mime::TEXT_XML,
|
||||
/// q(900)
|
||||
/// ),
|
||||
/// qitem("image/webp".parse().unwrap()),
|
||||
/// QualityItem::new(
|
||||
/// mime::STAR_STAR,
|
||||
/// q(800)
|
||||
/// ),
|
||||
/// ])
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # Notes
|
||||
/// * Using always Mime types to represent `media-range` differs from the ABNF.
|
||||
/// * **FIXME**: `accept-ext` is not supported.
|
||||
(Accept, "Accept") => (QualityItem<Mime>)+
|
||||
|
||||
test_accept {
|
||||
// Tests from the RFC
|
||||
// FIXME: Test fails, first value containing a "*" fails to parse
|
||||
// test_header!(
|
||||
// test1,
|
||||
// vec![b"audio/*; q=0.2, audio/basic"],
|
||||
// Some(HeaderField(vec![
|
||||
// QualityItem::new(Mime(TopLevel::Audio, SubLevel::Star, vec![]), q(200)),
|
||||
// qitem(Mime(TopLevel::Audio, SubLevel::Ext("basic".to_owned()), vec![])),
|
||||
// ])));
|
||||
test_header!(
|
||||
test1,
|
||||
vec![b"audio/*; q=0.2, audio/basic"],
|
||||
Some(HeaderField(vec![
|
||||
QualityItem::new("audio/*".parse().unwrap(), q(200)),
|
||||
qitem("audio/basic".parse().unwrap()),
|
||||
])));
|
||||
test_header!(
|
||||
test2,
|
||||
vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
|
||||
Some(HeaderField(vec![
|
||||
QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), q(500)),
|
||||
qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
|
||||
QualityItem::new(TEXT_PLAIN, q(500)),
|
||||
qitem(TEXT_HTML),
|
||||
QualityItem::new(
|
||||
Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_owned()), vec![]),
|
||||
"text/x-dvi".parse().unwrap(),
|
||||
q(800)),
|
||||
qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_owned()), vec![])),
|
||||
qitem("text/x-c".parse().unwrap()),
|
||||
])));
|
||||
// Custom tests
|
||||
test_header!(
|
||||
test3,
|
||||
vec![b"text/plain; charset=utf-8"],
|
||||
Some(Accept(vec![
|
||||
qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])),
|
||||
qitem(TEXT_PLAIN_UTF_8),
|
||||
])));
|
||||
test_header!(
|
||||
test4,
|
||||
vec![b"text/plain; charset=utf-8; q=0.5"],
|
||||
Some(Accept(vec![
|
||||
QualityItem::new(Mime(TopLevel::Text,
|
||||
SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]),
|
||||
QualityItem::new(TEXT_PLAIN_UTF_8,
|
||||
q(500)),
|
||||
])));
|
||||
|
||||
@@ -127,22 +122,22 @@ header! {
|
||||
impl Accept {
|
||||
/// A constructor to easily create `Accept: */*`.
|
||||
pub fn star() -> Accept {
|
||||
Accept(vec![qitem(mime!(Star/Star))])
|
||||
Accept(vec![qitem(mime::STAR_STAR)])
|
||||
}
|
||||
|
||||
/// A constructor to easily create `Accept: application/json`.
|
||||
pub fn json() -> Accept {
|
||||
Accept(vec![qitem(mime!(Application/Json))])
|
||||
Accept(vec![qitem(mime::APPLICATION_JSON)])
|
||||
}
|
||||
|
||||
/// A constructor to easily create `Accept: text/*`.
|
||||
pub fn text() -> Accept {
|
||||
Accept(vec![qitem(mime!(Text/Star))])
|
||||
Accept(vec![qitem(mime::TEXT_STAR)])
|
||||
}
|
||||
|
||||
/// A constructor to easily create `Accept: image/*`.
|
||||
pub fn image() -> Accept {
|
||||
Accept(vec![qitem(mime!(Image/Star))])
|
||||
Accept(vec![qitem(mime::IMAGE_STAR)])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use mime::Mime;
|
||||
use mime::{self, Mime};
|
||||
|
||||
header! {
|
||||
/// `Content-Type` header, defined in
|
||||
@@ -22,7 +22,8 @@ header! {
|
||||
/// ```
|
||||
///
|
||||
/// # Example values
|
||||
/// * `text/html; charset=ISO-8859-4`
|
||||
/// * `text/html; charset=utf-8`
|
||||
/// * `application/json
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
@@ -36,13 +37,12 @@ header! {
|
||||
/// ```
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, ContentType};
|
||||
/// use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
|
||||
/// use hyper::mime;
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
///
|
||||
/// headers.set(
|
||||
/// ContentType(Mime(TopLevel::Text, SubLevel::Html,
|
||||
/// vec![(Attr::Charset, Value::Utf8)]))
|
||||
/// ContentType(mime::TEXT_HTML)
|
||||
/// );
|
||||
/// ```
|
||||
(ContentType, "Content-Type") => [Mime]
|
||||
@@ -50,13 +50,8 @@ header! {
|
||||
test_content_type {
|
||||
test_header!(
|
||||
test1,
|
||||
// FIXME: Should be b"text/html; charset=ISO-8859-4" but mime crate lowercases
|
||||
// the whole value so parsing and formatting the value gives a different result
|
||||
vec![b"text/html; charset=iso-8859-4"],
|
||||
Some(HeaderField(Mime(
|
||||
TopLevel::Text,
|
||||
SubLevel::Html,
|
||||
vec![(Attr::Charset, Value::Ext("iso-8859-4".to_owned()))]))));
|
||||
vec![b"text/html"],
|
||||
Some(HeaderField(TEXT_HTML)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,45 +59,45 @@ impl ContentType {
|
||||
/// A constructor to easily create a `Content-Type: application/json` header.
|
||||
#[inline]
|
||||
pub fn json() -> ContentType {
|
||||
ContentType(mime!(Application/Json))
|
||||
ContentType(mime::APPLICATION_JSON)
|
||||
}
|
||||
|
||||
/// A constructor to easily create a `Content-Type: text/plain; charset=utf-8` header.
|
||||
#[inline]
|
||||
pub fn plaintext() -> ContentType {
|
||||
ContentType(mime!(Text/Plain; Charset=Utf8))
|
||||
ContentType(mime::TEXT_PLAIN_UTF_8)
|
||||
}
|
||||
|
||||
/// A constructor to easily create a `Content-Type: text/html; charset=utf-8` header.
|
||||
#[inline]
|
||||
pub fn html() -> ContentType {
|
||||
ContentType(mime!(Text/Html; Charset=Utf8))
|
||||
ContentType(mime::TEXT_HTML)
|
||||
}
|
||||
|
||||
/// A constructor to easily create a `Content-Type: application/www-form-url-encoded` header.
|
||||
#[inline]
|
||||
pub fn form_url_encoded() -> ContentType {
|
||||
ContentType(mime!(Application/WwwFormUrlEncoded))
|
||||
ContentType(mime::APPLICATION_WWW_FORM_URLENCODED)
|
||||
}
|
||||
/// A constructor to easily create a `Content-Type: image/jpeg` header.
|
||||
#[inline]
|
||||
pub fn jpeg() -> ContentType {
|
||||
ContentType(mime!(Image/Jpeg))
|
||||
ContentType(mime::IMAGE_JPEG)
|
||||
}
|
||||
|
||||
/// A constructor to easily create a `Content-Type: image/png` header.
|
||||
#[inline]
|
||||
pub fn png() -> ContentType {
|
||||
ContentType(mime!(Image/Png))
|
||||
ContentType(mime::IMAGE_PNG)
|
||||
}
|
||||
|
||||
/// A constructor to easily create a `Content-Type: application/octet-stream` header.
|
||||
#[inline]
|
||||
pub fn octet_stream() -> ContentType {
|
||||
ContentType(mime!(Application/OctetStream))
|
||||
ContentType(mime::APPLICATION_OCTET_STREAM)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ContentType {}
|
||||
|
||||
bench_header!(bench, ContentType, { vec![b"application/json; charset=utf-8".to_vec()] });
|
||||
bench_header!(bench, ContentType, { vec![b"application/json".to_vec()] });
|
||||
|
||||
@@ -905,9 +905,7 @@ mod tests {
|
||||
use http::{ServerTransaction, Http1Transaction};
|
||||
use bytes::BytesMut;
|
||||
|
||||
use mime::Mime;
|
||||
use mime::TopLevel::Text;
|
||||
use mime::SubLevel::Plain;
|
||||
use mime;
|
||||
|
||||
#[test]
|
||||
fn test_link() {
|
||||
@@ -956,7 +954,7 @@ mod tests {
|
||||
.push_media_desc(MediaDesc::Screen)
|
||||
.set_title("previous chapter")
|
||||
.set_title_star("title* unparsed")
|
||||
.set_media_type(Mime(Text, Plain, vec![]));
|
||||
.set_media_type(mime::TEXT_PLAIN);
|
||||
|
||||
let link_header = b"<http://example.com/TheBook/chapter2>; \
|
||||
rel=\"previous\"; anchor=\"../anchor/example/\"; \
|
||||
@@ -1015,7 +1013,7 @@ mod tests {
|
||||
.push_media_desc(MediaDesc::Screen)
|
||||
.set_title("previous chapter")
|
||||
.set_title_star("title* unparsed")
|
||||
.set_media_type(Mime(Text, Plain, vec![]));
|
||||
.set_media_type(mime::TEXT_PLAIN);
|
||||
|
||||
let link = Link::new(vec![link_value]);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! ## Mime
|
||||
//!
|
||||
//! Several header fields use MIME values for their contents. Keeping with the
|
||||
//! strongly-typed theme, the [mime](http://seanmonstar.github.io/mime.rs) crate
|
||||
//! strongly-typed theme, the [mime](https://docs.rs/mime) crate
|
||||
//! is used, such as `ContentType(pub Mime)`.
|
||||
|
||||
pub use self::accept::Accept;
|
||||
|
||||
@@ -696,11 +696,7 @@ impl PartialEq<HeaderName> for str {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fmt;
|
||||
use mime::Mime;
|
||||
use mime::TopLevel::Text;
|
||||
use mime::SubLevel::Plain;
|
||||
use super::{Headers, Header, Raw, ContentLength, ContentType,
|
||||
Accept, Host, qitem, SetCookie};
|
||||
use super::{Headers, Header, Raw, ContentLength, ContentType, Host, SetCookie};
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use test::Bencher;
|
||||
@@ -723,25 +719,6 @@ mod tests {
|
||||
assert_eq!(headers.get(), Some(&ContentLength(10)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_content_type() {
|
||||
let content_type = Header::parse_header(&b"text/plain".as_ref().into());
|
||||
assert_eq!(content_type.ok(), Some(ContentType(Mime(Text, Plain, vec![]))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accept() {
|
||||
let text_plain = qitem(Mime(Text, Plain, vec![]));
|
||||
let application_vendor = "application/vnd.github.v3.full+json; q=0.5".parse().unwrap();
|
||||
|
||||
let accept = Header::parse_header(&b"text/plain".as_ref().into());
|
||||
assert_eq!(accept.ok(), Some(Accept(vec![text_plain.clone()])));
|
||||
|
||||
let bytevec = b"application/vnd.github.v3.full+json; q=0.5, text/plain".as_ref().into();
|
||||
let accept = Header::parse_header(&bytevec);
|
||||
assert_eq!(accept.ok(), Some(Accept(vec![application_vendor, text_plain])));
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
struct CrazyLength(Option<bool>, usize);
|
||||
|
||||
@@ -882,7 +859,7 @@ mod tests {
|
||||
let mut headers = Headers::new();
|
||||
headers.set(ContentLength(10));
|
||||
assert_eq!(headers.len(), 1);
|
||||
headers.set(ContentType(Mime(Text, Plain, vec![])));
|
||||
headers.set(ContentType::json());
|
||||
assert_eq!(headers.len(), 2);
|
||||
// Redundant, should not increase count.
|
||||
headers.set(ContentLength(20));
|
||||
@@ -893,7 +870,7 @@ mod tests {
|
||||
fn test_clear() {
|
||||
let mut headers = Headers::new();
|
||||
headers.set(ContentLength(10));
|
||||
headers.set(ContentType(Mime(Text, Plain, vec![])));
|
||||
headers.set(ContentType::json());
|
||||
assert_eq!(headers.len(), 2);
|
||||
headers.clear();
|
||||
assert_eq!(headers.len(), 0);
|
||||
|
||||
@@ -20,7 +20,7 @@ extern crate futures_cpupool;
|
||||
extern crate httparse;
|
||||
extern crate language_tags;
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] pub extern crate mime;
|
||||
pub extern crate mime;
|
||||
extern crate base64;
|
||||
extern crate time;
|
||||
extern crate tokio_core as tokio;
|
||||
|
||||
Reference in New Issue
Block a user