mirror of https://github.com/rwf2/Rocket.git
Fairings, v3.
Modifying the `Rocket` structure just before launch doesn't make sense for several reasons: 1) those affects can't influence the launch, and 2) they won't be observed in tests. Thus, an `Attach` fairing kind was added that ameliorates these issues.
This commit is contained in:
parent
9c9740f966
commit
28a1ef0916
|
@ -0,0 +1,2 @@
|
|||
[global]
|
||||
token = 123
|
|
@ -6,10 +6,12 @@ extern crate rocket;
|
|||
use std::io::Cursor;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rocket::{Request, Data, Response};
|
||||
use rocket::{Request, State, Data, Response};
|
||||
use rocket::fairing::{AdHoc, Fairing, Info, Kind};
|
||||
use rocket::http::{Method, ContentType, Status};
|
||||
|
||||
struct Token(i64);
|
||||
|
||||
#[cfg(test)] mod tests;
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -56,13 +58,22 @@ fn hello() -> &'static str {
|
|||
"Hello, world!"
|
||||
}
|
||||
|
||||
#[get("/token")]
|
||||
fn token(token: State<Token>) -> String {
|
||||
format!("{}", token.0)
|
||||
}
|
||||
|
||||
fn rocket() -> rocket::Rocket {
|
||||
rocket::ignite()
|
||||
.mount("/", routes![hello])
|
||||
.mount("/", routes![hello, token])
|
||||
.attach(Counter::default())
|
||||
.attach(AdHoc::on_attach(|rocket| {
|
||||
println!("Adding token managed state...");
|
||||
let token_val = rocket.config().get_int("token").unwrap_or(-1);
|
||||
Ok(rocket.manage(Token(token_val)))
|
||||
}))
|
||||
.attach(AdHoc::on_launch(|rocket| {
|
||||
println!("Rocket is about to launch! Exciting! Here we go...");
|
||||
Ok(rocket)
|
||||
println!("Rocket is about to launch!");
|
||||
}))
|
||||
.attach(AdHoc::on_request(|req, _| {
|
||||
println!(" => Incoming request: {}", req);
|
||||
|
|
|
@ -9,6 +9,7 @@ fn rewrite_get_put() {
|
|||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some("Hello, fairings!".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn counts() {
|
||||
let rocket = rocket();
|
||||
|
@ -33,3 +34,13 @@ fn counts() {
|
|||
let mut response = req.dispatch_with(&rocket);
|
||||
assert_eq!(response.body_string(), Some("Get: 4\nPost: 1".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token() {
|
||||
let rocket = rocket();
|
||||
|
||||
// Ensure the token is '123', which is what we have in `Rocket.toml`.
|
||||
let mut req = MockRequest::new(Get, "/token");
|
||||
let mut res = req.dispatch_with(&rocket);
|
||||
assert_eq!(res.body_string(), Some("123".into()));
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use fairing::{Fairing, Kind, Info};
|
|||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// Use the [`on_launch`](#method.on_launch),
|
||||
/// Use the [`on_attach`](#method.on_attach), [`on_launch`](#method.on_launch),
|
||||
/// [`on_request`](#method.on_request), or [`on_response`](#method.on_response)
|
||||
/// constructors to create an `AdHoc` structure from a function or closure.
|
||||
/// Then, simply attach the structure to the `Rocket` instance.
|
||||
|
@ -25,28 +25,47 @@ use fairing::{Fairing, Kind, Info};
|
|||
/// use rocket::http::Method;
|
||||
///
|
||||
/// rocket::ignite()
|
||||
/// .attach(AdHoc::on_launch(|rocket| {
|
||||
/// .attach(AdHoc::on_launch(|_| {
|
||||
/// println!("Rocket is about to launch! Exciting! Here we go...");
|
||||
/// Ok(rocket)
|
||||
/// }))
|
||||
/// .attach(AdHoc::on_request(|req, _| {
|
||||
/// req.set_method(Method::Put);
|
||||
/// }));
|
||||
/// ```
|
||||
pub enum AdHoc {
|
||||
/// An ad-hoc **attach** fairing. Called when the fairing is attached.
|
||||
#[doc(hidden)]
|
||||
Attach(Box<Fn(Rocket) -> Result<Rocket, Rocket> + Send + Sync + 'static>),
|
||||
/// An ad-hoc **launch** fairing. Called just before Rocket launches.
|
||||
#[doc(hidden)]
|
||||
Launch(Box<Fn(Rocket) -> Result<Rocket, Rocket> + Send + Sync + 'static>),
|
||||
Launch(Box<Fn(&Rocket) + Send + Sync + 'static>),
|
||||
/// An ad-hoc **request** fairing. Called when a request is received.
|
||||
#[doc(hidden)]
|
||||
Request(Box<Fn(&mut Request, &Data) + Send + Sync + 'static>),
|
||||
/// An ad-hoc **response** fairing. Called when a response is ready to be
|
||||
/// sent to a client.
|
||||
#[doc(hidden)]
|
||||
Response(Box<Fn(&Request, &mut Response) + Send + Sync + 'static>)
|
||||
Response(Box<Fn(&Request, &mut Response) + Send + Sync + 'static>),
|
||||
}
|
||||
|
||||
impl AdHoc {
|
||||
/// Constructs an `AdHoc` attach fairing. The function `f` will be called by
|
||||
/// Rocket when this fairing is attached.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::fairing::AdHoc;
|
||||
///
|
||||
/// // The no-op attach fairing.
|
||||
/// let fairing = AdHoc::on_attach(|rocket| Ok(rocket));
|
||||
/// ```
|
||||
pub fn on_attach<F>(f: F) -> AdHoc
|
||||
where F: Fn(Rocket) -> Result<Rocket, Rocket> + Send + Sync + 'static
|
||||
{
|
||||
AdHoc::Attach(Box::new(f))
|
||||
}
|
||||
|
||||
/// Constructs an `AdHoc` launch fairing. The function `f` will be called by
|
||||
/// Rocket just prior to launching.
|
||||
///
|
||||
|
@ -55,11 +74,13 @@ impl AdHoc {
|
|||
/// ```rust
|
||||
/// use rocket::fairing::AdHoc;
|
||||
///
|
||||
/// // The no-op launch fairing.
|
||||
/// let fairing = AdHoc::on_launch(|rocket| Ok(rocket));
|
||||
/// // A fairing that prints a message just before launching.
|
||||
/// let fairing = AdHoc::on_launch(|rocket| {
|
||||
/// println!("Launching in T-3..2..1..");
|
||||
/// });
|
||||
/// ```
|
||||
pub fn on_launch<F>(f: F) -> AdHoc
|
||||
where F: Fn(Rocket) -> Result<Rocket, Rocket> + Send + Sync + 'static
|
||||
where F: Fn(&Rocket) + Send + Sync + 'static
|
||||
{
|
||||
AdHoc::Launch(Box::new(f))
|
||||
}
|
||||
|
@ -109,16 +130,43 @@ impl Fairing for AdHoc {
|
|||
fn info(&self) -> Info {
|
||||
use self::AdHoc::*;
|
||||
match *self {
|
||||
Launch(_) => Info { name: "AdHoc::Launch", kind: Kind::Launch },
|
||||
Request(_) => Info { name: "AdHoc::Request", kind: Kind::Request },
|
||||
Response(_) => Info { name: "AdHoc::Response", kind: Kind::Response }
|
||||
Attach(_) => {
|
||||
Info {
|
||||
name: "AdHoc::Attach",
|
||||
kind: Kind::Attach,
|
||||
}
|
||||
}
|
||||
Launch(_) => {
|
||||
Info {
|
||||
name: "AdHoc::Launch",
|
||||
kind: Kind::Launch,
|
||||
}
|
||||
}
|
||||
Request(_) => {
|
||||
Info {
|
||||
name: "AdHoc::Request",
|
||||
kind: Kind::Request,
|
||||
}
|
||||
}
|
||||
Response(_) => {
|
||||
Info {
|
||||
name: "AdHoc::Response",
|
||||
kind: Kind::Response,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_launch(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
|
||||
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
|
||||
match *self {
|
||||
AdHoc::Launch(ref launch_fn) => launch_fn(rocket),
|
||||
_ => Ok(rocket)
|
||||
AdHoc::Attach(ref callback) => callback(rocket),
|
||||
_ => Ok(rocket),
|
||||
}
|
||||
}
|
||||
|
||||
fn on_launch(&self, rocket: &Rocket) {
|
||||
if let AdHoc::Launch(ref callback) = *self {
|
||||
callback(rocket)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use fairing::{Fairing, Kind};
|
|||
#[derive(Default)]
|
||||
pub struct Fairings {
|
||||
all_fairings: Vec<Box<Fairing>>,
|
||||
attach_failure: bool,
|
||||
launch: Vec<&'static Fairing>,
|
||||
request: Vec<&'static Fairing>,
|
||||
response: Vec<&'static Fairing>,
|
||||
|
@ -15,11 +16,16 @@ impl Fairings {
|
|||
Fairings::default()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn attach(&mut self, fairing: Box<Fairing>) {
|
||||
pub fn attach(&mut self, fairing: Box<Fairing>, mut rocket: Rocket) -> Rocket {
|
||||
// Get the kind information.
|
||||
let kind = fairing.info().kind;
|
||||
|
||||
// Run the `on_attach` callback if this is an 'attach' fairing.
|
||||
if kind.is(Kind::Attach) {
|
||||
rocket = fairing.on_attach(rocket)
|
||||
.unwrap_or_else(|r| { self.attach_failure = true; r })
|
||||
}
|
||||
|
||||
// The `Fairings` structure separates `all_fairings` into kind groups so
|
||||
// we don't have to search through all fairings and do a comparison at
|
||||
// runtime. We need references since a single structure can be multiple
|
||||
|
@ -36,22 +42,25 @@ impl Fairings {
|
|||
// deallocating `Box<Fairing>` structures. As such, the references will
|
||||
// always be valid. Note: `ptr` doesn't point into the `Vec`, so
|
||||
// reallocations there are irrelvant. Instead, it points into the heap.
|
||||
let ptr: &'static Fairing = unsafe { ::std::mem::transmute(&*fairing) };
|
||||
//
|
||||
// Also, we don't save attach fairings since we don't need them anymore.
|
||||
if !kind.is_exactly(Kind::Attach) {
|
||||
let ptr: &'static Fairing = unsafe { ::std::mem::transmute(&*fairing) };
|
||||
|
||||
self.all_fairings.push(fairing);
|
||||
if kind.is(Kind::Launch) { self.launch.push(ptr); }
|
||||
if kind.is(Kind::Request) { self.request.push(ptr); }
|
||||
if kind.is(Kind::Response) { self.response.push(ptr); }
|
||||
self.all_fairings.push(fairing);
|
||||
if kind.is(Kind::Launch) { self.launch.push(ptr); }
|
||||
if kind.is(Kind::Request) { self.request.push(ptr); }
|
||||
if kind.is(Kind::Response) { self.response.push(ptr); }
|
||||
}
|
||||
|
||||
rocket
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn handle_launch(&mut self, mut rocket: Rocket) -> Option<Rocket> {
|
||||
let mut success = Some(());
|
||||
for f in &self.launch {
|
||||
rocket = f.on_launch(rocket).unwrap_or_else(|r| { success = None; r });
|
||||
pub fn handle_launch(&self, rocket: &Rocket) {
|
||||
for fairing in &self.launch {
|
||||
fairing.on_launch(rocket);
|
||||
}
|
||||
|
||||
success.map(|_| rocket)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -68,6 +77,10 @@ impl Fairings {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn had_failure(&self) -> bool {
|
||||
self.attach_failure
|
||||
}
|
||||
|
||||
pub fn pretty_print_counts(&self) {
|
||||
use term_painter::ToStyle;
|
||||
use term_painter::Color::{White, Magenta};
|
||||
|
@ -78,8 +91,10 @@ impl Fairings {
|
|||
|
||||
fn info_if_nonempty(kind: &str, fairings: &[&Fairing]) {
|
||||
let names: Vec<&str> = fairings.iter().map(|f| f.info().name).collect();
|
||||
info_!("{} {}: {}", White.paint(fairings.len()), kind,
|
||||
White.paint(names.join(", ")));
|
||||
info_!("{} {}: {}",
|
||||
White.paint(fairings.len()),
|
||||
kind,
|
||||
White.paint(names.join(", ")));
|
||||
}
|
||||
|
||||
info_if_nonempty("launch", &self.launch);
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::ops::BitOr;
|
|||
/// # Example
|
||||
///
|
||||
/// A simple `Info` structure that can be used for a `Fairing` that implements
|
||||
/// all three callbacks:
|
||||
/// all four callbacks:
|
||||
///
|
||||
/// ```
|
||||
/// use rocket::fairing::{Info, Kind};
|
||||
|
@ -18,7 +18,7 @@ use std::ops::BitOr;
|
|||
/// # let _unused_info =
|
||||
/// Info {
|
||||
/// name: "Example Fairing",
|
||||
/// kind: Kind::Launch | Kind::Request | Kind::Response
|
||||
/// kind: Kind::Attach | Kind::Launch | Kind::Request | Kind::Response
|
||||
/// }
|
||||
/// # ;
|
||||
/// ```
|
||||
|
@ -35,6 +35,7 @@ pub struct Info {
|
|||
/// A fairing can request any combination of any of the following kinds of
|
||||
/// callbacks:
|
||||
///
|
||||
/// * Attach
|
||||
/// * Launch
|
||||
/// * Request
|
||||
/// * Response
|
||||
|
@ -42,18 +43,20 @@ pub struct Info {
|
|||
/// Two `Kind` structures can be `or`d together to represent a combination. For
|
||||
/// instance, to represent a fairing that is both a launch and request fairing,
|
||||
/// use `Kind::Launch | Kind::Request`. Similarly, to represent a fairing that
|
||||
/// is all three kinds, use `Kind::Launch | Kind::Request | Kind::Response`.
|
||||
/// is only an attach fairing, use `Kind::Attach`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Kind(usize);
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
impl Kind {
|
||||
/// `Kind` flag representing a request for an 'attach' callback.
|
||||
pub const Attach: Kind = Kind(0b0001);
|
||||
/// `Kind` flag representing a request for a 'launch' callback.
|
||||
pub const Launch: Kind = Kind(0b001);
|
||||
pub const Launch: Kind = Kind(0b0010);
|
||||
/// `Kind` flag representing a request for a 'request' callback.
|
||||
pub const Request: Kind = Kind(0b010);
|
||||
pub const Request: Kind = Kind(0b0100);
|
||||
/// `Kind` flag representing a request for a 'response' callback.
|
||||
pub const Response: Kind = Kind(0b100);
|
||||
pub const Response: Kind = Kind(0b1000);
|
||||
|
||||
/// Returns `true` if `self` is a superset of `other`. In other words,
|
||||
/// returns `true` if all of the kinds in `other` are also in `self`.
|
||||
|
@ -77,6 +80,26 @@ impl Kind {
|
|||
pub fn is(self, other: Kind) -> bool {
|
||||
(other.0 & self.0) == other.0
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is exactly `other`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::fairing::Kind;
|
||||
///
|
||||
/// let launch_and_req = Kind::Launch | Kind::Request;
|
||||
/// assert!(launch_and_req.is_exactly(Kind::Launch | Kind::Request));
|
||||
///
|
||||
/// assert!(!launch_and_req.is_exactly(Kind::Launch));
|
||||
/// assert!(!launch_and_req.is_exactly(Kind::Request));
|
||||
/// assert!(!launch_and_req.is_exactly(Kind::Response));
|
||||
/// assert!(!launch_and_req.is_exactly(Kind::Launch | Kind::Response));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn is_exactly(self, other: Kind) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for Kind {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Fairings: structured interposition at launch, request, and response time.
|
||||
//! Fairings: callbacks at attach, launch, request, and response time.
|
||||
//!
|
||||
//! Fairings allow for structured interposition at various points in the
|
||||
//! application lifetime. Fairings can be seen as a restricted form of
|
||||
|
@ -26,7 +26,7 @@
|
|||
//! ```
|
||||
//!
|
||||
//! Once a fairing is attached, Rocket will execute it at the appropiate time,
|
||||
//! which varies depending on the fairing type. See the
|
||||
//! which varies depending on the fairing implementation. See the
|
||||
//! [`Fairing`](/rocket/fairing/trait.Fairing.html) trait documentation for more
|
||||
//! information on the dispatching of fairing methods.
|
||||
//!
|
||||
|
@ -37,7 +37,8 @@
|
|||
//! fairing callbacks may not be commutative, it is important to communicate to
|
||||
//! the user every consequence of a fairing. Furthermore, a `Fairing` should
|
||||
//! take care to act locally so that the actions of other `Fairings` are not
|
||||
//! jeopardized.
|
||||
//! jeopardized. For instance, unless it is made abundantly clear, a fairing
|
||||
//! should not rewrite every request.
|
||||
use {Rocket, Request, Response, Data};
|
||||
|
||||
mod fairings;
|
||||
|
@ -90,12 +91,29 @@ pub use self::info_kind::{Info, Kind};
|
|||
///
|
||||
/// ## Fairing Callbacks
|
||||
///
|
||||
/// There are three kinds of fairing callbacks: launch, request, and response.
|
||||
/// As mentioned above, a fairing can request any combination of these callbacks
|
||||
/// through the `kind` field of the `Info` structure returned from the `info`
|
||||
/// method. Rocket will only invoke the callbacks set in the `kind` field.
|
||||
/// There are four kinds of fairing callbacks: attach, launch, request, and
|
||||
/// response. As mentioned above, a fairing can request any combination of these
|
||||
/// callbacks through the `kind` field of the `Info` structure returned from the
|
||||
/// `info` method. Rocket will only invoke the callbacks set in the `kind`
|
||||
/// field.
|
||||
///
|
||||
/// The three callback kinds are as follows:
|
||||
/// The four callback kinds are as follows:
|
||||
///
|
||||
/// * **Attach (`on_attach`)**
|
||||
///
|
||||
/// An attach callback, represented by the
|
||||
/// [`on_attach`](/rocket/fairing/trait.Fairing.html#method.on_attach)
|
||||
/// method, is called when a fairing is first attached via the
|
||||
/// [`attach`](/rocket/struct.Rocket.html#method.attach) method. The state
|
||||
/// of the `Rocket` instance is, at this point, not finalized, as the user
|
||||
/// may still add additional information to the `Rocket` instance. As a
|
||||
/// result, it is unwise to depend on the state of the `Rocket` instance.
|
||||
///
|
||||
/// An attach callback can arbitrarily modify the `Rocket` instance being
|
||||
/// constructed. It returns `Ok` if it would like launching to proceed
|
||||
/// nominally and `Err` otherwise. If a launch callback returns `Err`,
|
||||
/// launch will be aborted. All attach callbacks are executed on `launch`,
|
||||
/// even if one or more signal a failure.
|
||||
///
|
||||
/// * **Launch (`on_launch`)**
|
||||
///
|
||||
|
@ -103,10 +121,8 @@ pub use self::info_kind::{Info, Kind};
|
|||
/// [`on_launch`](/rocket/fairing/trait.Fairing.html#method.on_launch)
|
||||
/// method, is called immediately before the Rocket application has
|
||||
/// launched. At this point, Rocket has opened a socket for listening but
|
||||
/// has not yet begun accepting connections. A launch callback can
|
||||
/// arbitrarily modify the `Rocket` instance being launched. It returns `Ok`
|
||||
/// if it would like launching to proceed nominally and `Err` otherwise. If
|
||||
/// a launch callback returns `Err`, launch is aborted.
|
||||
/// has not yet begun accepting connections. A launch callback can inspect
|
||||
/// the `Rocket` instance being launched.
|
||||
///
|
||||
/// * **Request (`on_request`)**
|
||||
///
|
||||
|
@ -136,15 +152,15 @@ pub use self::info_kind::{Info, Kind};
|
|||
/// # Implementing
|
||||
///
|
||||
/// A `Fairing` implementation has one required method: `info`. A `Fairing` can
|
||||
/// also implement any of the available callbacks: `on_launch`, `on_request`,
|
||||
/// and `on_response`. A `Fairing` _must_ set the appropriate callback kind in
|
||||
/// the `kind` field of the returned `Info` structure from `info` for a callback
|
||||
/// to actually be issued by Rocket.
|
||||
/// also implement any of the available callbacks: `on_attach`, `on_launch`,
|
||||
/// `on_request`, and `on_response`. A `Fairing` _must_ set the appropriate
|
||||
/// callback kind in the `kind` field of the returned `Info` structure from
|
||||
/// `info` for a callback to actually be issued by Rocket.
|
||||
///
|
||||
/// A `Fairing` must be `Send + Sync + 'static`. This means that the fairing
|
||||
/// must be sendable across thread boundaries (`Send`), thread-safe (`Sync`),
|
||||
/// and have no non-`'static` reference (`'static`). Note that these bounds _do
|
||||
/// not_ prohibit a `Fairing` from having state: the state need simply be
|
||||
/// not_ prohibit a `Fairing` from holding state: the state need simply be
|
||||
/// thread-safe and statically available or heap allocated.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -154,7 +170,7 @@ pub use self::info_kind::{Info, Kind};
|
|||
/// guards](/rocket/request/trait.FromRequest.html) and [managed
|
||||
/// state](/rocket/request/struct.State.html), it would require us to annotate
|
||||
/// every `GET` and `POST` request with custom types, polluting handler
|
||||
/// signatures. Instead, we can create a simple fairing that does this globally.
|
||||
/// signatures. Instead, we can create a simple fairing that acts globally.
|
||||
///
|
||||
/// The `Counter` fairing below records the number of all `GET` and `POST`
|
||||
/// requests received. It makes these counts available at a special `'/counts'`
|
||||
|
@ -238,23 +254,38 @@ pub trait Fairing: Send + Sync + 'static {
|
|||
/// fn info(&self) -> Info {
|
||||
/// Info {
|
||||
/// name: "My Custom Fairing",
|
||||
/// kind: Kind::Launch | Kind::Response
|
||||
/// kind: Kind::Attach | Kind::Launch | Kind::Response
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn info(&self) -> Info;
|
||||
|
||||
/// The launch callback. Returns `Ok` if launch should proceed and `Err` if
|
||||
/// The attach callback. Returns `Ok` if launch should proceed and `Err` if
|
||||
/// launch should be aborted.
|
||||
///
|
||||
/// This method is called just prior to launching an application if
|
||||
/// `Kind::Launch` is in the `kind` field of the `Info` structure for this
|
||||
/// fairing. The `rocket` parameter is the `Rocket` instance that was built
|
||||
/// for this application.
|
||||
/// This method is called when a fairing is attached if `Kind::Attach` is in
|
||||
/// the `kind` field of the `Info` structure for this fairing. The `rocket`
|
||||
/// parameter is the `Rocket` instance that is currently being built for
|
||||
/// this application.
|
||||
///
|
||||
/// ## Default Implementation
|
||||
///
|
||||
/// The default implementation of this method simply returns `Ok(rocket)`.
|
||||
fn on_launch(&self, rocket: Rocket) -> Result<Rocket, Rocket> { Ok(rocket) }
|
||||
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> { Ok(rocket) }
|
||||
|
||||
/// The launch callback.
|
||||
///
|
||||
/// This method is called just prior to launching the application if
|
||||
/// `Kind::Launch` is in the `kind` field of the `Info` structure for this
|
||||
/// fairing. The `&Rocket` parameter curresponds to the application that
|
||||
/// will be launched.
|
||||
///
|
||||
/// ## Default Implementation
|
||||
///
|
||||
/// The default implementation of this method does nothing.
|
||||
#[allow(unused_variables)]
|
||||
fn on_launch(&self, rocket: &Rocket) {}
|
||||
|
||||
/// The request callback.
|
||||
///
|
||||
|
@ -263,9 +294,11 @@ pub trait Fairing: Send + Sync + 'static {
|
|||
/// `&mut Request` parameter is the incoming request, and the `&Data`
|
||||
/// parameter is the incoming data in the request.
|
||||
///
|
||||
/// ## Default Implementation
|
||||
///
|
||||
/// The default implementation of this method does nothing.
|
||||
#[allow(unused_variables)]
|
||||
fn on_request(&self, request: &mut Request, data: &Data) { }
|
||||
fn on_request(&self, request: &mut Request, data: &Data) {}
|
||||
|
||||
/// The response callback.
|
||||
///
|
||||
|
@ -274,7 +307,9 @@ pub trait Fairing: Send + Sync + 'static {
|
|||
/// this fairing. The `&Request` parameter is the request that was routed,
|
||||
/// and the `&mut Response` parameter is the resulting response.
|
||||
///
|
||||
/// ## Default Implementation
|
||||
///
|
||||
/// The default implementation of this method does nothing.
|
||||
#[allow(unused_variables)]
|
||||
fn on_response(&self, request: &Request, response: &mut Response) { }
|
||||
fn on_response(&self, request: &Request, response: &mut Response) {}
|
||||
}
|
||||
|
|
|
@ -284,7 +284,6 @@ impl Rocket {
|
|||
for route in matches {
|
||||
// Retrieve and set the requests parameters.
|
||||
info_!("Matched: {}", route);
|
||||
// FIXME: Users should not be able to use this.
|
||||
request.set_params(route);
|
||||
|
||||
// Dispatch the request to the handler.
|
||||
|
@ -598,25 +597,37 @@ impl Rocket {
|
|||
/// use rocket::Rocket;
|
||||
/// use rocket::fairing::AdHoc;
|
||||
///
|
||||
/// fn youll_see(rocket: Rocket) -> Result<Rocket, Rocket> {
|
||||
/// println!("Rocket is about to launch! You just see...");
|
||||
/// Ok(rocket)
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// # if false { // We don't actually want to launch the server in an example.
|
||||
/// rocket::ignite()
|
||||
/// .attach(AdHoc::on_launch(youll_see))
|
||||
/// .attach(AdHoc::on_launch(|_| {
|
||||
/// println!("Rocket is about to launch! You just see...");
|
||||
/// }))
|
||||
/// .launch();
|
||||
/// # }
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn attach<F: Fairing>(mut self, fairing: F) -> Self {
|
||||
self.fairings.attach(Box::new(fairing));
|
||||
// Attach the fairings, which requires us to move `self`.
|
||||
let mut fairings = mem::replace(&mut self.fairings, Fairings::new());
|
||||
self = fairings.attach(Box::new(fairing), self);
|
||||
|
||||
// Make sure we keep the fairings around!
|
||||
self.fairings = fairings;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn prelaunch_check(&self) -> Option<LaunchError> {
|
||||
if self.router.has_collisions() {
|
||||
Some(LaunchError::from(LaunchErrorKind::Collision))
|
||||
} else if self.fairings.had_failure() {
|
||||
Some(LaunchError::from(LaunchErrorKind::FailedFairing))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the application server and begins listening for and dispatching
|
||||
/// requests to mounted routes and catchers. Unless there is an error, this
|
||||
/// function does not return and blocks until program termination.
|
||||
|
@ -637,9 +648,9 @@ impl Rocket {
|
|||
/// rocket::ignite().launch();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn launch(mut self) -> LaunchError {
|
||||
if self.router.has_collisions() {
|
||||
return LaunchError::from(LaunchErrorKind::Collision);
|
||||
pub fn launch(self) -> LaunchError {
|
||||
if let Some(error) = self.prelaunch_check() {
|
||||
return error;
|
||||
}
|
||||
|
||||
self.fairings.pretty_print_counts();
|
||||
|
@ -657,15 +668,8 @@ impl Rocket {
|
|||
Err(e) => return LaunchError::from(e)
|
||||
};
|
||||
|
||||
// Run all of the launch fairings.
|
||||
let mut fairings = mem::replace(&mut self.fairings, Fairings::new());
|
||||
self = match fairings.handle_launch(self) {
|
||||
Some(rocket) => rocket,
|
||||
None => return LaunchError::from(LaunchErrorKind::FailedFairing)
|
||||
};
|
||||
|
||||
// Make sure we keep the request/response fairings!
|
||||
self.fairings = fairings;
|
||||
// Run the launch fairings.
|
||||
self.fairings.handle_launch(&self);
|
||||
|
||||
launch_info!("🚀 {} {}{}",
|
||||
White.paint("Rocket has launched from"),
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
//! ```
|
||||
|
||||
use ::{Rocket, Request, Response, Data};
|
||||
use http::{Method, Header, Cookie};
|
||||
use http::{Method, Status, Header, Cookie};
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
|
@ -201,11 +201,12 @@ impl<'r> MockRequest<'r> {
|
|||
|
||||
/// Dispatch this request using a given instance of Rocket.
|
||||
///
|
||||
/// Returns the body of the response if there was a response. The return
|
||||
/// value is `None` if any of the following occurs:
|
||||
///
|
||||
/// 1. The returned body was not valid UTF8.
|
||||
/// 2. The application failed to respond.
|
||||
/// It is possible that the supplied `rocket` instance contains malformed
|
||||
/// input such as colliding or invalid routes or failed fairings. When this
|
||||
/// is the case, the returned `Response` will contain a status of
|
||||
/// `InternalServerError`, and the body will contain the error that
|
||||
/// occurred. In all other cases, the returned `Response` will be that of
|
||||
/// the application.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -234,6 +235,13 @@ impl<'r> MockRequest<'r> {
|
|||
/// # }
|
||||
/// ```
|
||||
pub fn dispatch_with<'s>(&'s mut self, rocket: &'r Rocket) -> Response<'s> {
|
||||
if let Some(error) = rocket.prelaunch_check() {
|
||||
return Response::build()
|
||||
.status(Status::InternalServerError)
|
||||
.sized_body(::std::io::Cursor::new(error.to_string()))
|
||||
.finalize()
|
||||
}
|
||||
|
||||
let data = ::std::mem::replace(&mut self.data, Data::local(vec![]));
|
||||
rocket.dispatch(&mut self.request, data)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue