Redocument ContentType.

This commit is contained in:
Sergio Benitez 2016-12-19 20:40:21 -08:00
parent ddbd7966f7
commit d44c61f1af
3 changed files with 119 additions and 58 deletions

View File

@ -6,17 +6,43 @@ use http::Header;
use http::hyper::mime::Mime; use http::hyper::mime::Mime;
use router::Collider; use router::Collider;
/// Typed representation of HTTP Content-Types. /// Representation of HTTP Content-Types.
/// ///
/// This type wraps raw HTTP `Content-Type`s in a type-safe manner. It provides /// # Usage
/// methods to create and test against common HTTP content-types. It also ///
/// provides methods to parse HTTP Content-Type values /// ContentTypes should rarely be created directly. Instead, an associated
/// ([from_str](#method.from_str)) and to return the ContentType associated with /// constant should be used; one is declared for most commonly used content
/// a file extension ([from_ext](#method.from_extension)). /// types.
///
/// ## Example
///
/// A Content-Type of `text/html; charset=utf-8` can be insantiated via the
/// `HTML` constant:
///
/// ```rust
/// use rocket::http::ContentType;
///
/// let html = ContentType::HTML;
/// ```
///
/// # Header
///
/// `ContentType` implements `Into<Header>`. As such, it can be used in any
/// context where an `Into<Header>` is expected:
///
/// ```rust
/// use rocket::http::ContentType;
/// use rocket::response::Response;
///
/// let response = Response::build().header(ContentType::HTML).finalize();
/// ```
#[derive(Debug, Clone, PartialEq, Hash)] #[derive(Debug, Clone, PartialEq, Hash)]
pub struct ContentType { pub struct ContentType {
/// The "type" component of the Content-Type.
pub ttype: Cow<'static, str>, pub ttype: Cow<'static, str>,
/// The "subtype" component of the Content-Type.
pub subtype: Cow<'static, str>, pub subtype: Cow<'static, str>,
/// Semicolon-seperated parameters associated with the Content-Type.
pub params: Option<Cow<'static, str>> pub params: Option<Cow<'static, str>>
} }
@ -45,7 +71,8 @@ macro_rules! ctrs {
}; };
)+ )+
/// Returns `true` if this ContentType is known to Rocket. /// Returns `true` if this ContentType is known to Rocket, that is,
/// there is an associated constant for `self`.
pub fn is_known(&self) -> bool { pub fn is_known(&self) -> bool {
match (&*self.ttype, &*self.subtype) { match (&*self.ttype, &*self.subtype) {
$( $(
@ -63,7 +90,9 @@ macro_rules! ctrs {
#[doc="</i>/<i>"] #[doc="</i>/<i>"]
#[doc=$sub] #[doc=$sub]
#[doc="</i>."] #[doc="</i>."]
/// Paramaters are not taken into account when doing that check. ///
/// Paramaters are not taken into account when doing this check.
#[inline(always)]
pub fn $check_name(&self) -> bool { pub fn $check_name(&self) -> bool {
self.ttype == $top && self.subtype == $sub self.ttype == $top && self.subtype == $sub
} }
@ -72,34 +101,26 @@ macro_rules! ctrs {
} }
impl ContentType { impl ContentType {
#[inline(always)] ctrs! {
pub fn new<T, S>(ttype: T, subtype: S) -> ContentType "any", Any, is_any => "*", "*",
where T: Into<Cow<'static, str>>, S: Into<Cow<'static, str>> "HTML", HTML, is_html => "text", "html" ; "charset=utf-8",
{ "Plain", Plain, is_plain => "text", "plain" ; "charset=utf-8",
ContentType { "JSON", JSON, is_json => "application", "json",
ttype: ttype.into(), "form", Form, is_form => "application", "x-www-form-urlencoded",
subtype: subtype.into(), "JavaScript", JavaScript, is_javascript => "application", "javascript",
params: None "CSS", CSS, is_css => "text", "css" ; "charset=utf-8",
} "data form", DataForm, is_data_form => "multipart", "form-data",
"XML", XML, is_xml => "text", "xml" ; "charset=utf-8",
"PNG", PNG, is_png => "image", "png",
"GIF", GIF, is_gif => "image", "gif",
"BMP", BMP, is_bmp => "image", "bmp",
"JPEG", JPEG, is_jpeg => "image", "jpeg",
"PDF", PDF, is_pdf => "application", "pdf"
} }
#[inline(always)]
pub fn with_params<T, S, P>(ttype: T, subtype: S, params: Option<P>) -> ContentType
where T: Into<Cow<'static, str>>,
S: Into<Cow<'static, str>>,
P: Into<Cow<'static, str>>
{
ContentType {
ttype: ttype.into(),
subtype: subtype.into(),
params: params.map(|p| p.into())
}
}
/// Returns the Content-Type associated with the extension `ext`. Not all /// Returns the Content-Type associated with the extension `ext`. Not all
/// extensions are recognized. If an extensions is not recognized, then this /// extensions are recognized. If an extensions is not recognized, then this
/// method returns a ContentType of `any`. The currently recognized /// method returns a ContentType of `Any`. The currently recognized
/// extensions are: txt, html, htm, xml, js, css, json, png, gif, bmp, jpeg, /// extensions are: txt, html, htm, xml, js, css, json, png, gif, bmp, jpeg,
/// jpg, and pdf. /// jpg, and pdf.
/// ///
@ -139,26 +160,63 @@ impl ContentType {
} }
} }
ctrs! { /// Creates a new `ContentType` with type `ttype` and subtype `subtype`.
"any", Any, is_any => "*", "*", /// This should be _only_ to construct uncommon Content-Types or custom
"form", Form, is_form => "application", "x-www-form-urlencoded", /// Content-Types. Use an associated constant for common Content-Types.
"data form", DataForm, is_data_form => "multipart", "form-data", ///
"JSON", JSON, is_json => "application", "json", /// # Example
"XML", XML, is_xml => "text", "xml" ; "charset=utf-8", ///
"HTML", HTML, is_html => "text", "html" ; "charset=utf-8", /// Create a custom `application/x-person` Content-Type:
"Plain", Plain, is_plain => "text", "plain" ; "charset=utf-8", ///
"JavaScript", JavaScript, is_javascript => "application", "javascript", /// ```rust
"CSS", CSS, is_css => "text", "css" ; "charset=utf-8", /// use rocket::http::ContentType;
"PNG", PNG, is_png => "image", "png", ///
"GIF", GIF, is_gif => "image", "gif", /// let custom = ContentType::new("application", "x-person");
"BMP", BMP, is_bmp => "image", "bmp", /// assert_eq!(custom.to_string(), "application/x-person".to_string());
"JPEG", JPEG, is_jpeg => "image", "jpeg", /// ```
"PDF", PDF, is_pdf => "application", "pdf" #[inline(always)]
pub fn new<T, S>(ttype: T, subtype: S) -> ContentType
where T: Into<Cow<'static, str>>, S: Into<Cow<'static, str>>
{
ContentType {
ttype: ttype.into(),
subtype: subtype.into(),
params: None
}
}
/// Creates a new `ContentType` with type `ttype`, subtype `subtype`, and
/// optionally parameters `params`, a semicolon-seperated list of
/// parameters. This should be _only_ to construct uncommon Content-Types or
/// custom Content-Types. Use an associated constant for common
/// Content-Types.
///
/// # Example
///
/// Create a custom `application/x-id; id=1` Content-Type:
///
/// ```rust
/// use rocket::http::ContentType;
///
/// let id = ContentType::with_params("application", "x-id", Some("id=1"));
/// assert_eq!(id.to_string(), "application/x-id; id=1".to_string());
/// ```
#[inline(always)]
pub fn with_params<T, S, P>(ttype: T, subtype: S, params: Option<P>) -> ContentType
where T: Into<Cow<'static, str>>,
S: Into<Cow<'static, str>>,
P: Into<Cow<'static, str>>
{
ContentType {
ttype: ttype.into(),
subtype: subtype.into(),
params: params.map(|p| p.into())
}
} }
} }
impl Default for ContentType { impl Default for ContentType {
/// Returns a ContentType of `any`, or `*/*`. /// Returns a ContentType of `Any`, or `*/*`.
#[inline(always)] #[inline(always)]
fn default() -> ContentType { fn default() -> ContentType {
ContentType::Any ContentType::Any
@ -323,6 +381,8 @@ impl fmt::Display for ContentType {
} }
} }
/// Creates a new `Header` with name `Content-Type` and the value set to the
/// HTTP rendering of this Content-Type.
impl Into<Header<'static>> for ContentType { impl Into<Header<'static>> for ContentType {
#[inline] #[inline]
fn into(self) -> Header<'static> { fn into(self) -> Header<'static> {

View File

@ -39,4 +39,5 @@ pub use self::stream::Stream;
pub use self::failure::Failure; pub use self::failure::Failure;
#[doc(inline)] pub use self::content::Content; #[doc(inline)] pub use self::content::Content;
/// Type alias for the `Result` of a `Responder::respond` call.
pub type Result<'r> = ::std::result::Result<self::Response<'r>, ::http::Status>; pub type Result<'r> = ::std::result::Result<self::Response<'r>, ::http::Status>;

View File

@ -19,14 +19,14 @@ use response::{Response, Stream};
/// ///
/// # Return Value /// # Return Value
/// ///
/// A `Responder` returns an `Ok(Response)` or an `Err(Status)`. /// A `Responder` returns an `Ok(Response)` or an `Err(Status)`:
/// ///
/// An `Ok` variant means that the `Responder` was successful in generating a /// * An `Ok` variant means that the `Responder` was successful in generating
/// new `Response`. The `Response` will be written out to the client. /// a `Response`. The `Response` will be written out to the client.
/// ///
/// An `Err` variant means that the `Responder` could not or did not generate a /// * An `Err` variant means that the `Responder` could not or did not
/// `Response`. The contained `Status` will be used to find the relevant error /// generate a `Response`. The contained `Status` will be used to find the
/// catcher to use to generate a proper response. /// relevant error catcher which then generates an error response.
/// ///
/// # Provided Implementations /// # Provided Implementations
/// ///
@ -37,7 +37,7 @@ use response::{Response, Stream};
/// ///
/// * **&str** /// * **&str**
/// ///
/// Sets the `Content-Type`t to `text/plain`. The string is used as the body /// Sets the `Content-Type` to `text/plain`. The string is used as the body
/// of the response, which is fixed size and not streamed. To stream a raw /// of the response, which is fixed size and not streamed. To stream a raw
/// string, use `Stream::from(Cursor::new(string))`. /// string, use `Stream::from(Cursor::new(string))`.
/// ///
@ -52,15 +52,15 @@ use response::{Response, Stream};
/// Streams the `File` to the client. This is essentially an alias to /// Streams the `File` to the client. This is essentially an alias to
/// `Stream::from(file)`. /// `Stream::from(file)`.
/// ///
/// * **impl Responder for ()** /// * **()**
/// ///
/// Responds with an empty body. No Content-Type is set. /// Responds with an empty body. No Content-Type is set.
/// ///
/// * **Option&lt;T>** /// * **Option&lt;T>**
/// ///
/// If the `Option` is `Some`, the wrapped responder is used to respond to /// If the `Option` is `Some`, the wrapped responder is used to respond to
/// respond to the client. Otherwise, an `Err` with status **404 Not Found** /// the client. Otherwise, an `Err` with status **404 Not Found** is
/// is returned and a warning is printed to the console. /// returned and a warning is printed to the console.
/// ///
/// * **Result&lt;T, E>** _where_ **E: Debug** /// * **Result&lt;T, E>** _where_ **E: Debug**
/// ///