mirror of https://github.com/rwf2/Rocket.git
Document Responder. Further document Flash. Implement Debug for most Responder types.
This commit is contained in:
parent
7beec53889
commit
129268506e
|
@ -26,7 +26,7 @@ impl<'a, S, E> IntoOutcome<S, (StatusCode, E), Data> for Result<S, E> {
|
||||||
/// fn submit(var: T) -> ... { ... }
|
/// fn submit(var: T) -> ... { ... }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// In this example, `T` can be any type that implements `FromData.`
|
/// In this example, `T` can be any type that implements `FromData`.
|
||||||
///
|
///
|
||||||
/// # Outcomes
|
/// # Outcomes
|
||||||
///
|
///
|
||||||
|
|
|
@ -3,6 +3,7 @@ use http::hyper::{header, FreshHyperResponse};
|
||||||
use http::mime::{Mime, TopLevel, SubLevel};
|
use http::mime::{Mime, TopLevel, SubLevel};
|
||||||
use http::ContentType;
|
use http::ContentType;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Content<T: Responder>(pub ContentType, pub T);
|
pub struct Content<T: Responder>(pub ContentType, pub T);
|
||||||
|
|
||||||
impl<T: Responder> Responder for Content<T> {
|
impl<T: Responder> Responder for Content<T> {
|
||||||
|
@ -14,6 +15,7 @@ impl<T: Responder> Responder for Content<T> {
|
||||||
|
|
||||||
macro_rules! impl_data_type_responder {
|
macro_rules! impl_data_type_responder {
|
||||||
($name:ident: $top:ident/$sub:ident) => (
|
($name:ident: $top:ident/$sub:ident) => (
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct $name<T: Responder>(pub T);
|
pub struct $name<T: Responder>(pub T);
|
||||||
|
|
||||||
impl<T: Responder> Responder for $name<T> {
|
impl<T: Responder> Responder for $name<T> {
|
||||||
|
|
|
@ -5,10 +5,11 @@ use response::{self, Responder};
|
||||||
use request::{self, Request, FromRequest};
|
use request::{self, Request, FromRequest};
|
||||||
use http::hyper::{HyperSetCookie, HyperCookiePair, FreshHyperResponse};
|
use http::hyper::{HyperSetCookie, HyperCookiePair, FreshHyperResponse};
|
||||||
|
|
||||||
|
// The name of the actual flash cookie.
|
||||||
const FLASH_COOKIE_NAME: &'static str = "_flash";
|
const FLASH_COOKIE_NAME: &'static str = "_flash";
|
||||||
|
|
||||||
/// Sets a "flash" cookies that will be removed the next time it is accessed.
|
/// Sets a "flash" cookie that will be removed when it is accessed. The
|
||||||
/// The anologous type on the request side is
|
/// anologous request type is
|
||||||
/// [FlashMessage](/rocket/request/type.FlashMessage.html).
|
/// [FlashMessage](/rocket/request/type.FlashMessage.html).
|
||||||
///
|
///
|
||||||
/// This type makes it easy to send messages across requests. It is typically
|
/// This type makes it easy to send messages across requests. It is typically
|
||||||
|
@ -30,12 +31,56 @@ const FLASH_COOKIE_NAME: &'static str = "_flash";
|
||||||
/// [FlashMessage](/rocket/request/type.FlashMessage.html) type and the
|
/// [FlashMessage](/rocket/request/type.FlashMessage.html) type and the
|
||||||
/// [name](#method.name) and [msg](#method.msg) methods.
|
/// [name](#method.name) and [msg](#method.msg) methods.
|
||||||
///
|
///
|
||||||
/// # Responder
|
/// # Response
|
||||||
///
|
///
|
||||||
/// The `Responder` implementation for `Flash` sets the message cookie and then
|
/// The `Responder` implementation for `Flash` sets the message cookie and then
|
||||||
/// uses the passed in responder `res` to complete the response. In other words,
|
/// uses the passed in responder `res` to complete the response. In other words,
|
||||||
/// it simply sets a cookie and delagates the rest of the response handling to
|
/// it simply sets a cookie and delagates the rest of the response handling to
|
||||||
/// the wrapped responder.
|
/// the wrapped responder.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// The following complete Rocket application illustrates the use of a `Flash`
|
||||||
|
/// message on both the request and response sides.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// #
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// #
|
||||||
|
/// use rocket::response::{Flash, Redirect};
|
||||||
|
/// use rocket::request::FlashMessage;
|
||||||
|
///
|
||||||
|
/// #[post("/login/<name>")]
|
||||||
|
/// fn login(name: &str) -> Result<&'static str, Flash<Redirect>> {
|
||||||
|
/// if name == "special_user" {
|
||||||
|
/// Ok("Hello, special user!")
|
||||||
|
/// } else {
|
||||||
|
/// Err(Flash::error(Redirect::to("/"), "Invalid username."))
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[get("/")]
|
||||||
|
/// fn index(flash: Option<FlashMessage>) -> String {
|
||||||
|
/// flash.map(|msg| format!("{}: {}", msg.name(), msg.msg()))
|
||||||
|
/// .unwrap_or_else(|| "Welcome!".to_string())
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// # if false { // We don't actually want to launch the server in an example.
|
||||||
|
/// rocket::ignite().mount("/", routes![login, index]).launch()
|
||||||
|
/// # }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// On the response side (in `login`), a `Flash` error message is set if some
|
||||||
|
/// fictional authentication failed, and the user is redirected to `"/"`. On the
|
||||||
|
/// request side (in `index`), the handler emits the flash message if there is
|
||||||
|
/// one and otherwise emits a standard welcome message. Note that if the user
|
||||||
|
/// were to refresh the index page after viewing a flash message, the user would
|
||||||
|
/// receive the standard welcome message.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Flash<R> {
|
pub struct Flash<R> {
|
||||||
name: String,
|
name: String,
|
||||||
message: String,
|
message: String,
|
||||||
|
@ -124,6 +169,10 @@ impl<R: Responder> Flash<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the message cookie and then uses the wrapped responder to complete the
|
||||||
|
/// response. In other words, simply sets a cookie and delagates the rest of the
|
||||||
|
/// response handling to the wrapped responder. As a result, the `Outcome` of
|
||||||
|
/// the response is the `Outcome` of the wrapped `Responder`.
|
||||||
impl<R: Responder> Responder for Flash<R> {
|
impl<R: Responder> Responder for Flash<R> {
|
||||||
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> response::Outcome<'b> {
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> response::Outcome<'b> {
|
||||||
trace_!("Flash: setting message: {}:{}", self.name, self.message);
|
trace_!("Flash: setting message: {}:{}", self.name, self.message);
|
||||||
|
@ -133,6 +182,7 @@ impl<R: Responder> Responder for Flash<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Flash<()> {
|
impl Flash<()> {
|
||||||
|
/// Constructs a new message with the given name and message.
|
||||||
fn named(name: &str, msg: &str) -> Flash<()> {
|
fn named(name: &str, msg: &str) -> Flash<()> {
|
||||||
Flash {
|
Flash {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
@ -152,7 +202,11 @@ impl Flash<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is Type-Aliased in Request.
|
/// Retrieves a flash message from a flash cookie and deletes the flash cookie.
|
||||||
|
/// If there is no flash cookie, an empty `Err` is returned.
|
||||||
|
///
|
||||||
|
/// The suggested use is through an `Option` and the `FlashMessage` type alias
|
||||||
|
/// in `request`: `Option<FlashMessage>`.
|
||||||
impl<'r> FromRequest<'r> for Flash<()> {
|
impl<'r> FromRequest<'r> for Flash<()> {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
//! Types and traits to build and send responses.
|
//! Types and traits to build and send responses.
|
||||||
//!
|
//!
|
||||||
//! The return type of a Rocket handler can be any type that implements the
|
//! The return type of a Rocket handler can be any type that implements the
|
||||||
//! [Responder](trait.Responder.html) trait. This module contains several useful
|
//! [Responder](trait.Responder.html) trait. This module contains several such
|
||||||
//! types that implement this trait.
|
//! types.
|
||||||
|
//!
|
||||||
|
//! # Composing
|
||||||
|
//!
|
||||||
|
//! Many of the built-in `Responder` types _chain_ responses: they take in
|
||||||
|
//! another `Responder` and simply add, remove, or change information in the
|
||||||
|
//! response. In other words, many `Responder` types are built to compose well.
|
||||||
|
//! As a result, you'll often have types of the form `A<B<C>>` consisting of
|
||||||
|
//! three `Responder`s `A`, `B`, and `C`. This is normal and encouraged as the
|
||||||
|
//! type names typically illustrate the intended response.
|
||||||
|
|
||||||
mod responder;
|
mod responder;
|
||||||
mod redirect;
|
mod redirect;
|
||||||
|
|
|
@ -19,7 +19,69 @@ impl<'a, T, E> IntoOutcome<(), (), (StatusCode, FreshHyperResponse<'a>)> for Res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// # 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.
|
||||||
pub trait Responder {
|
pub trait Responder {
|
||||||
|
/// 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.
|
||||||
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a>;
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::io::{Read, Write, ErrorKind};
|
use std::io::{Read, Write, ErrorKind};
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
use response::{Responder, Outcome};
|
use response::{Responder, Outcome};
|
||||||
use http::hyper::FreshHyperResponse;
|
use http::hyper::FreshHyperResponse;
|
||||||
|
@ -26,6 +27,12 @@ impl<T: Read> Stream<T> {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Debug> Debug for Stream<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Stream({:?})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Read> Responder for Stream<T> {
|
impl<T: Read> Responder for Stream<T> {
|
||||||
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
||||||
let mut stream = match res.start() {
|
let mut stream = match res.start() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use response::{Responder, Outcome};
|
use response::{Responder, Outcome};
|
||||||
use http::hyper::{StatusCode, FreshHyperResponse};
|
use http::hyper::{StatusCode, FreshHyperResponse};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct StatusResponse<R: Responder> {
|
pub struct StatusResponse<R: Responder> {
|
||||||
status: StatusCode,
|
status: StatusCode,
|
||||||
responder: R,
|
responder: R,
|
||||||
|
|
Loading…
Reference in New Issue