Skip to content

Commit

Permalink
Prefix 'content' responder names with 'Raw'.
Browse files Browse the repository at this point in the history
The primary aim of this commit is to reduce confusion between
'content::Json' and 'rocket::serde::json::Json' be renaming the former
to 'content::RawJson'. The complete changes in this PR are:

  * All responders in the 'content' module are prefixed with 'Raw'.
  * The 'content::Custom' responder was removed entirely.
  * The 'Plain' responder is now 'RawText'.
  * The 'content' API docs point to the 'serde' responders.
  * The docs and examples were updated accordingly.
  • Loading branch information
SergioBenitez committed Jul 20, 2021
1 parent 179be25 commit cc06216
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 100 deletions.
3 changes: 2 additions & 1 deletion core/lib/src/fs/named_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use crate::request::Request;
use crate::response::{self, Responder};
use crate::http::ContentType;

/// A [`Responder`] that sends a file with a Content-Type based on its name.
/// A [`Responder`] that sends file data with a Content-Type based on its
/// file extension.
///
/// # Example
///
Expand Down
86 changes: 30 additions & 56 deletions core/lib/src/response/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
//!
//! # Usage
//!
//! Each type wraps a given responder. The `Responder` implementation of each
//! type replaces the Content-Type of the wrapped responder and delegates the
//! remainder of the response to the wrapped responder. This allows for setting
//! the Content-Type of a type that doesn't set it itself or for overriding one
//! that does.
//!
//! The [`Custom`] type allows responding with _any_ `Content-Type`. As a
//! convenience, `(ContentType, R)` where `R: Responder` is _also_ a
//! `Responder`, identical to `Custom`.
//! Each type in this module is a `Responder` that wraps an existing
//! `Responder`, overwriting the `Content-Type` of the response but otherwise
//! delegating the response to the wrapped responder. As a convenience,
//! `(ContentType, R)` where `R: Responder` is _also_ a `Responder` that
//! overrides the `Content-Type` to the value in `.0`:
//!
//! ```rust
//! # use rocket::get;
Expand All @@ -21,55 +17,24 @@
//! (ContentType::HTML, "Is this HTML? <p>Sure, why not!</p>")
//! }
//! ```
//!
//! # Example
//!
//! The following snippet creates an `Html` content response for a string.
//! Normally, raw strings set their response Content-Type to `text/plain`. By
//! using the `Html` content response, the Content-Type will be set to
//! `text/html` instead.
//! The following snippet creates a `RawHtml` response from a string. Normally,
//! raw strings set their response Content-Type to `text/plain`. By using the
//! `RawHtml` content response, the Content-Type will be set to `text/html`
//! instead:
//!
//! ```rust
//! use rocket::response::content;
//!
//! # #[allow(unused_variables)]
//! let response = content::Html("<h1>Hello, world!</h1>");
//! let response = content::RawHtml("<h1>Hello, world!</h1>");
//! ```
use crate::request::Request;
use crate::response::{self, Response, Responder};
use crate::http::ContentType;

/// Sets the Content-Type of a `Responder` to a chosen value.
///
/// Delegates the remainder of the response to the wrapped responder.
///
/// # Example
///
/// Set the Content-Type of a string to PDF.
///
/// ```rust
/// use rocket::response::content::Custom;
/// use rocket::http::ContentType;
///
/// # #[allow(unused_variables)]
/// let response = Custom(ContentType::PDF, "Hi.");
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Custom<R>(pub ContentType, pub R);

/// Overrides the Content-Type of the response to the wrapped `ContentType` then
/// delegates the remainder of the response to the wrapped responder.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Custom<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Response::build()
.merge(self.1.respond_to(req)?)
.header(self.0)
.ok()
}
}

macro_rules! ctrs {
($($name:ident: $ct:ident, $name_str:expr, $ct_str:expr),+) => {
$(
Expand All @@ -80,14 +45,21 @@ macro_rules! ctrs {
#[doc="</i>."]
///
/// Delegates the remainder of the response to the wrapped responder.
///
/// **Note:** Unlike types like [`Json`](crate::serde::json::Json)
/// and [`MsgPack`](crate::serde::msgpack::MsgPack), this type _does
/// not_ serialize data in any way. You should _always_ use those
/// types to respond with serializable data. Additionally, you
/// should _always_ use [`NamedFile`](crate::fs::NamedFile), which
/// automatically sets a `Content-Type`, to respond with file data.
#[derive(Debug, Clone, PartialEq)]
pub struct $name<R>(pub R);

/// Sets the Content-Type of the response then delegates the
/// remainder of the response to the wrapped responder.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for $name<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Custom(ContentType::$ct, self.0).respond_to(req)
(ContentType::$ct, self.0).respond_to(req)
}
}
)+
Expand All @@ -96,18 +68,20 @@ macro_rules! ctrs {

ctrs! {
// FIXME: Add a note that this is _not_ `serde::Json`.
Json: JSON, "JSON", "application/json",
Xml: XML, "XML", "text/xml",
MsgPack: MsgPack, "MessagePack", "application/msgpack",
Html: HTML, "HTML", "text/html",
Plain: Plain, "plain text", "text/plain",
Css: CSS, "CSS", "text/css",
JavaScript: JavaScript, "JavaScript", "application/javascript"
RawJson: JSON, "JSON", "application/json",
RawXml: XML, "XML", "text/xml",
RawMsgPack: MsgPack, "MessagePack", "application/msgpack",
RawHtml: HTML, "HTML", "text/html",
RawText: Text, "plain text", "text/plain",
RawCss: CSS, "CSS", "text/css",
RawJavaScript: JavaScript, "JavaScript", "application/javascript"
}

impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for (ContentType, R) {
#[inline(always)]
fn respond_to(self, request: &'r Request<'_>) -> response::Result<'o> {
Custom(self.0, self.1).respond_to(request)
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Response::build()
.merge(self.1.respond_to(req)?)
.header(self.0)
.ok()
}
}
4 changes: 2 additions & 2 deletions core/lib/src/serde/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl<'r, T: Serialize> Responder<'r, 'static> for Json<T> {
Status::InternalServerError
})?;

content::Json(string).respond_to(req)
content::RawJson(string).respond_to(req)
}
}

Expand Down Expand Up @@ -299,7 +299,7 @@ impl<'v, T: Deserialize<'v> + Send> form::FromFormField<'v> for Json<T> {
/// and a fixed-size body with the serialized value.
impl<'r> Responder<'r, 'static> for Value {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
content::Json(self.to_string()).respond_to(req)
content::RawJson(self.to_string()).respond_to(req)
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/lib/src/serde/msgpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ impl<'r, T: Serialize> Responder<'r, 'static> for MsgPack<T> {
Status::InternalServerError
})?;

content::MsgPack(buf).respond_to(req)
content::RawMsgPack(buf).respond_to(req)
}
}

Expand Down
7 changes: 4 additions & 3 deletions core/lib/tests/head_handling.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[macro_use] extern crate rocket;

use rocket::{http::Status, response::content};
use rocket::http::Status;
use rocket::response::content::RawJson;

#[get("/empty")]
fn empty() -> Status {
Expand All @@ -13,8 +14,8 @@ fn index() -> &'static str {
}

#[head("/other")]
fn other() -> content::Json<&'static str> {
content::Json("{ 'hi': 'hello' }")
fn other() -> RawJson<&'static str> {
RawJson("{ 'hi': 'hello' }")
}

mod head_handling_tests {
Expand Down
6 changes: 3 additions & 3 deletions examples/cookies/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
mod session;
mod message;

use rocket::response::content::Html;
use rocket::response::content::RawHtml;
use rocket_dyn_templates::Template;

#[get("/")]
fn index() -> Html<&'static str> {
Html(r#"<a href="message">Set a Message</a> or <a href="session">Use Sessions</a>."#)
fn index() -> RawHtml<&'static str> {
RawHtml(r#"<a href="message">Set a Message</a> or <a href="session">Use Sessions</a>."#)
}

#[launch]
Expand Down
8 changes: 4 additions & 4 deletions examples/error-handling/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ fn forced_error(code: u16) -> Status {
}

#[catch(404)]
fn general_not_found() -> content::Html<&'static str> {
content::Html(r#"
fn general_not_found() -> content::RawHtml<&'static str> {
content::RawHtml(r#"
<p>Hmm... What are you looking for?</p>
Say <a href="/hello/Sergio/100">hello!</a>
"#)
}

#[catch(404)]
fn hello_not_found(req: &Request<'_>) -> content::Html<String> {
content::Html(format!("\
fn hello_not_found(req: &Request<'_>) -> content::RawHtml<String> {
content::RawHtml(format!("\
<p>Sorry, but '{}' is not a valid path!</p>\
<p>Try visiting /hello/&lt;name&gt;/&lt;age&gt; instead.</p>",
req.uri()))
Expand Down
6 changes: 3 additions & 3 deletions examples/pastebin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::io;

use rocket::data::{Data, ToByteUnit};
use rocket::http::uri::Absolute;
use rocket::response::content::Plain;
use rocket::response::content::RawText;
use rocket::tokio::fs::{self, File};

use crate::paste_id::PasteId;
Expand All @@ -24,8 +24,8 @@ async fn upload(paste: Data<'_>) -> io::Result<String> {
}

#[get("/<id>")]
async fn retrieve(id: PasteId<'_>) -> Option<Plain<File>> {
File::open(id.file_path()).await.map(Plain).ok()
async fn retrieve(id: PasteId<'_>) -> Option<RawText<File>> {
File::open(id.file_path()).await.map(RawText).ok()
}

#[delete("/<id>")]
Expand Down
32 changes: 16 additions & 16 deletions examples/responders/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,26 +89,26 @@ fn maybe_redir(name: &str) -> Result<&'static str, Redirect> {
use rocket::Request;
use rocket::response::content;

// NOTE: This example explicitly uses the `Json` type from `response::content`
// for demonstration purposes. In a real application, _always_ prefer to use
// `rocket::serde::json::Json` instead!
// NOTE: This example explicitly uses the `RawJson` type from
// `response::content` for demonstration purposes. In a real application,
// _always_ prefer to use `rocket::serde::json::Json` instead!

// In a `GET` request and all other non-payload supporting request types, the
// preferred media type in the Accept header is matched against the `format` in
// the route attribute. Because the client can use non-specific media types like
// `*/*` in `Accept`, these first two routes would collide without `rank`.
#[get("/content", format = "xml", rank = 1)]
fn xml() -> content::Xml<&'static str> {
content::Xml("<payload>I'm here</payload>")
fn xml() -> content::RawXml<&'static str> {
content::RawXml("<payload>I'm here</payload>")
}

#[get("/content", format = "json", rank = 2)]
fn json() -> content::Json<&'static str> {
content::Json(r#"{ "payload": "I'm here" }"#)
fn json() -> content::RawJson<&'static str> {
content::RawJson(r#"{ "payload": "I'm here" }"#)
}

#[catch(404)]
fn not_found(request: &Request<'_>) -> content::Html<String> {
fn not_found(request: &Request<'_>) -> content::RawHtml<String> {
let html = match request.format() {
Some(ref mt) if !(mt.is_xml() || mt.is_html()) => {
format!("<p>'{}' requests are not supported.</p>", mt)
Expand All @@ -118,40 +118,40 @@ fn not_found(request: &Request<'_>) -> content::Html<String> {
request.uri())
};

content::Html(html)
content::RawHtml(html)
}

/******************************* `Either` Responder ***************************/

use rocket::Either;
use rocket::response::content::{Json, MsgPack};
use rocket::response::content::{RawJson, RawMsgPack};
use rocket::http::uncased::AsUncased;

// NOTE: In a real application, we'd use `Json` and `MsgPack` from
// `rocket::serde`, which perform automatic serialization of responses and
// automatically set the `Content-Type`.
#[get("/content/<kind>")]
fn json_or_msgpack(kind: &str) -> Either<Json<&'static str>, MsgPack<&'static [u8]>> {
fn json_or_msgpack(kind: &str) -> Either<RawJson<&'static str>, RawMsgPack<&'static [u8]>> {
if kind.as_uncased() == "msgpack" {
Either::Right(MsgPack(&[162, 104, 105]))
Either::Right(RawMsgPack(&[162, 104, 105]))
} else {
Either::Left(Json("\"hi\""))
Either::Left(RawJson("\"hi\""))
}
}

/******************************* Custom Responder *****************************/

use std::borrow::Cow;

use rocket::response::content::Html;
use rocket::response::content::RawHtml;

#[derive(Responder)]
enum StoredData {
File(Option<NamedFile>),
String(Cow<'static, str>),
Bytes(Vec<u8>),
#[response(status = 401)]
NotAuthorized(Html<&'static str>),
NotAuthorized(RawHtml<&'static str>),
}

#[derive(FromFormField, UriDisplayQuery)]
Expand All @@ -170,7 +170,7 @@ async fn custom(kind: Option<Kind>) -> StoredData {
},
Some(Kind::String) => StoredData::String("Hey, I'm some data.".into()),
Some(Kind::Bytes) => StoredData::Bytes(vec![72, 105]),
None => StoredData::NotAuthorized(Html("No no no!"))
None => StoredData::NotAuthorized(RawHtml("No no no!"))
}
}

Expand Down
6 changes: 3 additions & 3 deletions examples/state/src/managed_hit_count.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::sync::atomic::{AtomicUsize, Ordering};

use rocket::State;
use rocket::response::content;
use rocket::response::content::RawHtml;
use rocket::fairing::AdHoc;

struct HitCount(AtomicUsize);

#[get("/")]
fn index(hit_count: &State<HitCount>) -> content::Html<String> {
fn index(hit_count: &State<HitCount>) -> RawHtml<String> {
let count = hit_count.0.fetch_add(1, Ordering::Relaxed) + 1;
content::Html(format!("Your visit is recorded!<br /><br />Visits: {}", count))
RawHtml(format!("Your visit is recorded!<br /><br />Visits: {}", count))
}

pub fn stage() -> AdHoc {
Expand Down
6 changes: 3 additions & 3 deletions examples/templating/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ mod tera;

#[cfg(test)] mod tests;

use rocket::response::content::Html;
use rocket::response::content::RawHtml;
use rocket_dyn_templates::Template;

#[get("/")]
fn index() -> Html<&'static str> {
Html(r#"See <a href="tera">Tera</a> or <a href="hbs">Handlebars</a>."#)
fn index() -> RawHtml<&'static str> {
RawHtml(r#"See <a href="tera">Tera</a> or <a href="hbs">Handlebars</a>."#)
}

#[launch]
Expand Down
Loading

0 comments on commit cc06216

Please sign in to comment.