2016-03-28 09:34:09 +00:00
|
|
|
use std::fs::File;
|
|
|
|
use std::fmt;
|
|
|
|
|
2016-10-04 00:09:13 +00:00
|
|
|
use http::mime::{Mime, TopLevel, SubLevel};
|
|
|
|
use http::hyper::{header, FreshHyperResponse, StatusCode};
|
2016-10-25 09:17:49 +00:00
|
|
|
use outcome::{self, IntoOutcome};
|
|
|
|
use outcome::Outcome::*;
|
2016-11-03 16:05:41 +00:00
|
|
|
use response::Stream;
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
|
2016-10-25 14:42:10 +00:00
|
|
|
/// Type alias for the `Outcome` of a `Responder`.
|
2016-10-25 09:17:49 +00:00
|
|
|
pub type Outcome<'a> = outcome::Outcome<(), (), (StatusCode, FreshHyperResponse<'a>)>;
|
2016-10-04 00:09:13 +00:00
|
|
|
|
2016-10-25 11:03:50 +00:00
|
|
|
impl<'a, T, E> IntoOutcome<(), (), (StatusCode, FreshHyperResponse<'a>)> for Result<T, E> {
|
|
|
|
fn into_outcome(self) -> Outcome<'a> {
|
|
|
|
match self {
|
|
|
|
Ok(_) => Success(()),
|
|
|
|
Err(_) => Failure(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-03 14:09:01 +00:00
|
|
|
/// Trait implemented by types that send a response to clients.
|
|
|
|
///
|
|
|
|
/// Types that implement this trait can be used as the return type of a handler,
|
|
|
|
/// as illustrated below:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// #[get("/")]
|
|
|
|
/// fn index() -> T { ... }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// In this example, `T` can be any type that implements `Responder`.
|
|
|
|
///
|
|
|
|
/// # Outcomes
|
|
|
|
///
|
|
|
|
/// The returned [Outcome](/rocket/outcome/index.html) of a `respond` call
|
|
|
|
/// determines how the response will be processed, if at all.
|
|
|
|
///
|
|
|
|
/// * **Success**
|
|
|
|
///
|
|
|
|
/// An `Outcome` of `Success` indicates that the responder was successful in
|
|
|
|
/// sending the response to the client. No further processing will occur as a
|
|
|
|
/// result.
|
|
|
|
///
|
|
|
|
/// * **Failure**
|
|
|
|
///
|
|
|
|
/// An `Outcome` of `Failure` indicates that the responder failed after
|
|
|
|
/// beginning a response. The response is incomplete, and there is no way to
|
|
|
|
/// salvage the response. No further processing will occur.
|
|
|
|
///
|
|
|
|
/// * **Forward**(StatusCode, FreshHyperResponse<'a>)
|
|
|
|
///
|
|
|
|
/// If the `Outcome` is `Forward`, the response will be forwarded to the
|
|
|
|
/// designated error [Catcher](/rocket/struct.Catcher.html) for the given
|
|
|
|
/// `StatusCode`. This requires that a response wasn't started and thus is
|
|
|
|
/// still fresh.
|
|
|
|
///
|
2016-11-03 16:05:41 +00:00
|
|
|
/// # Provided Implementations
|
|
|
|
///
|
|
|
|
/// Rocket implements `Responder` for several standard library types. Their
|
|
|
|
/// behavior is documented here. Note that the `Result` implementation is
|
|
|
|
/// overloaded, allowing for two `Responder`s to be used at once, depending on
|
|
|
|
/// the variant.
|
|
|
|
///
|
|
|
|
/// * **impl<'a> Responder for &'a str**
|
|
|
|
///
|
|
|
|
/// Sets the `Content-Type`t to `text/plain` if it is not already set. Sends
|
|
|
|
/// the string as the body of the response.
|
|
|
|
///
|
|
|
|
/// * **impl Responder for String**
|
|
|
|
///
|
|
|
|
/// Sets the `Content-Type`t to `text/html` if it is not already set. Sends
|
|
|
|
/// the string as the body of the response.
|
|
|
|
///
|
|
|
|
/// * **impl Responder for File**
|
|
|
|
///
|
|
|
|
/// Streams the `File` to the client. This is essentially an alias to
|
|
|
|
/// Stream<File>.
|
|
|
|
///
|
2016-12-10 03:53:13 +00:00
|
|
|
/// * **impl Responder for ()**
|
|
|
|
///
|
|
|
|
/// Responds with an empty body.
|
|
|
|
///
|
2016-11-03 16:05:41 +00:00
|
|
|
/// * **impl<T: Responder> Responder for Option<T>**
|
|
|
|
///
|
|
|
|
/// If the `Option` is `Some`, the wrapped responder is used to respond to
|
|
|
|
/// respond to the client. Otherwise, the response is forwarded to the 404
|
|
|
|
/// error catcher and a warning is printed to the console.
|
|
|
|
///
|
|
|
|
/// * **impl<T: Responder, E: Debug> Responder for Result<T, E>**
|
|
|
|
///
|
|
|
|
/// If the `Result` is `Ok`, the wrapped responder is used to respond to the
|
|
|
|
/// client. Otherwise, the response is forwarded to the 500 error catcher
|
|
|
|
/// and the error is printed to the console using the `Debug`
|
|
|
|
/// implementation.
|
|
|
|
///
|
|
|
|
/// * **impl<T: Responder, E: Responder + Debug> Responder for Result<T, E>**
|
|
|
|
///
|
|
|
|
/// If the `Result` is `Ok`, the wrapped `Ok` responder is used to respond
|
|
|
|
/// to the client. If the `Result` is `Err`, the wrapped error responder is
|
|
|
|
/// used to respond to the client.
|
|
|
|
///
|
2016-11-03 14:09:01 +00:00
|
|
|
/// # Implementation Tips
|
|
|
|
///
|
|
|
|
/// This section describes a few best practices to take into account when
|
|
|
|
/// implementing `Responder`.
|
|
|
|
///
|
|
|
|
/// ## Debug
|
|
|
|
///
|
|
|
|
/// A type implementing `Responder` should implement the `Debug` trait when
|
|
|
|
/// possible. This is because the `Responder` implementation for `Result`
|
|
|
|
/// requires its `Err` type to implement `Debug`. Therefore, a type implementing
|
|
|
|
/// `Debug` can more easily be composed.
|
|
|
|
///
|
|
|
|
/// ## Check Before Changing
|
|
|
|
///
|
|
|
|
/// Unless a given type is explicitly designed to change some information in
|
|
|
|
/// ther esponse, it should first _check_ that some information hasn't been set
|
|
|
|
/// before _changing_ that information. For example, before setting the
|
|
|
|
/// `Content-Type` header of a response, first check that the header hasn't been
|
|
|
|
/// set.
|
2016-03-28 09:34:09 +00:00
|
|
|
pub trait Responder {
|
2016-11-03 14:09:01 +00:00
|
|
|
/// Attempts to write a response to `res`.
|
|
|
|
///
|
|
|
|
/// If writing the response successfully completes, an outcome of `Success`
|
|
|
|
/// is returned. If writing the response begins but fails, an outcome of
|
|
|
|
/// `Failure` is returned. If writing a response fails before writing
|
|
|
|
/// anything out, an outcome of `Forward` can be returned, which causes the
|
|
|
|
/// response to be written by the appropriate error catcher instead.
|
2016-11-02 16:39:41 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a>;
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
|
2016-11-03 16:05:41 +00:00
|
|
|
/// Sets the `Content-Type`t to `text/plain` if it is not already set. Sends the
|
|
|
|
/// string as the body of the response.
|
2016-03-28 09:34:09 +00:00
|
|
|
impl<'a> Responder for &'a str {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
2016-08-27 01:37:28 +00:00
|
|
|
if res.headers().get::<header::ContentType>().is_none() {
|
|
|
|
let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
|
|
|
|
res.headers_mut().set(header::ContentType(mime));
|
|
|
|
}
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
res.send(self.as_bytes()).into_outcome()
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Responder for String {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-08-27 01:37:28 +00:00
|
|
|
if res.headers().get::<header::ContentType>().is_none() {
|
|
|
|
let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
|
|
|
|
res.headers_mut().set(header::ContentType(mime));
|
|
|
|
}
|
2016-10-09 11:29:02 +00:00
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
res.send(self.as_bytes()).into_outcome()
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-03 16:05:41 +00:00
|
|
|
/// Essentially aliases Stream<File>.
|
2016-03-28 09:34:09 +00:00
|
|
|
impl Responder for File {
|
2016-11-03 16:05:41 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
|
|
|
Stream::from(self).respond(res)
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-10 03:53:13 +00:00
|
|
|
/// Empty response.
|
|
|
|
impl Responder for () {
|
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
|
|
|
res.send(&[]).into_outcome()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-28 09:34:09 +00:00
|
|
|
impl<T: Responder> Responder for Option<T> {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-10-09 11:29:02 +00:00
|
|
|
if let Some(ref mut val) = *self {
|
|
|
|
val.respond(res)
|
|
|
|
} else {
|
|
|
|
warn_!("Response was `None`.");
|
2016-10-25 09:17:49 +00:00
|
|
|
Forward((StatusCode::NotFound, res))
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
|
|
|
// prepend with `default` when using impl specialization
|
2016-10-25 09:17:49 +00:00
|
|
|
default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-10-09 11:29:02 +00:00
|
|
|
match *self {
|
|
|
|
Ok(ref mut val) => val.respond(res),
|
|
|
|
Err(ref e) => {
|
|
|
|
error_!("{:?}", e);
|
2016-10-25 09:17:49 +00:00
|
|
|
Forward((StatusCode::InternalServerError, res))
|
2016-10-09 11:29:02 +00:00
|
|
|
}
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-04-23 02:48:03 +00:00
|
|
|
match *self {
|
|
|
|
Ok(ref mut responder) => responder.respond(res),
|
2016-09-30 22:20:11 +00:00
|
|
|
Err(ref mut responder) => responder.respond(res),
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|