mirror of https://github.com/rwf2/Rocket.git
Asyncify 'Handler'. Rename 'ErrorHandlerFuture' to 'CatcherFuture'.
This commit is contained in:
parent
f7cd455558
commit
1704ff7743
|
@ -18,7 +18,7 @@ use std::path::{PathBuf, Path};
|
||||||
|
|
||||||
use rocket::{Request, Data, Route};
|
use rocket::{Request, Data, Route};
|
||||||
use rocket::http::{Method, uri::Segments, ext::IntoOwned};
|
use rocket::http::{Method, uri::Segments, ext::IntoOwned};
|
||||||
use rocket::handler::{Handler, HandlerFuture, Outcome};
|
use rocket::handler::{Handler, Outcome};
|
||||||
use rocket::response::{NamedFile, Redirect};
|
use rocket::response::{NamedFile, Redirect};
|
||||||
|
|
||||||
/// A bitset representing configurable options for the [`StaticFiles`] handler.
|
/// A bitset representing configurable options for the [`StaticFiles`] handler.
|
||||||
|
@ -276,34 +276,34 @@ impl Into<Vec<Route>> for StaticFiles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_dir<'r, P>(opt: Options, req: &'r Request<'_>, data: Data, path: P) -> Outcome<'r>
|
async fn handle_dir<'r, P>(opt: Options, r: &'r Request<'_>, d: Data, p: P) -> Outcome<'r>
|
||||||
where P: AsRef<Path>
|
where P: AsRef<Path>
|
||||||
{
|
{
|
||||||
if opt.contains(Options::NormalizeDirs) && !req.uri().path().ends_with('/') {
|
if opt.contains(Options::NormalizeDirs) && !r.uri().path().ends_with('/') {
|
||||||
let new_path = req.uri().map_path(|p| p.to_owned() + "/")
|
let new_path = r.uri().map_path(|p| p.to_owned() + "/")
|
||||||
.expect("adding a trailing slash to a known good path results in a valid path")
|
.expect("adding a trailing slash to a known good path results in a valid path")
|
||||||
.into_owned();
|
.into_owned();
|
||||||
|
|
||||||
return Outcome::from_or_forward(req, data, Redirect::permanent(new_path));
|
return Outcome::from_or_forward(r, d, Redirect::permanent(new_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opt.contains(Options::Index) {
|
if !opt.contains(Options::Index) {
|
||||||
return Outcome::forward(data);
|
return Outcome::forward(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = NamedFile::open(path.as_ref().join("index.html")).await.ok();
|
let file = NamedFile::open(p.as_ref().join("index.html")).await.ok();
|
||||||
Outcome::from_or_forward(req, data, file)
|
Outcome::from_or_forward(r, d, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
impl Handler for StaticFiles {
|
impl Handler for StaticFiles {
|
||||||
fn handle<'r, 's: 'r>(&'s self, req: &'r Request<'_>, data: Data) -> HandlerFuture<'r> {
|
async fn handle<'r, 's: 'r>(&'s self, req: &'r Request<'_>, data: Data) -> Outcome<'r> {
|
||||||
// If this is not the route with segments, handle it only if the user
|
// If this is not the route with segments, handle it only if the user
|
||||||
// requested a handling of index files.
|
// requested a handling of index files.
|
||||||
let current_route = req.route().expect("route while handling");
|
let current_route = req.route().expect("route while handling");
|
||||||
let is_segments_route = current_route.uri.path().ends_with(">");
|
let is_segments_route = current_route.uri.path().ends_with(">");
|
||||||
if !is_segments_route {
|
if !is_segments_route {
|
||||||
let result = handle_dir(self.options, req, data, &self.root);
|
return handle_dir(self.options, req, data, &self.root).await;
|
||||||
return Box::pin(async move { result.await });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we're handling segments. Get the segments as a `PathBuf`,
|
// Otherwise, we're handling segments. Get the segments as a `PathBuf`,
|
||||||
|
@ -314,12 +314,10 @@ impl Handler for StaticFiles {
|
||||||
.and_then(|segments| segments.into_path_buf(allow_dotfiles).ok())
|
.and_then(|segments| segments.into_path_buf(allow_dotfiles).ok())
|
||||||
.map(|path| self.root.join(path));
|
.map(|path| self.root.join(path));
|
||||||
|
|
||||||
Box::pin(async move {
|
match path {
|
||||||
match path {
|
Some(p) if p.is_dir() => handle_dir(self.options, req, data, p).await,
|
||||||
Some(p) if p.is_dir() => handle_dir(self.options, req, data, p).await,
|
Some(p) => Outcome::from_or_forward(req, data, NamedFile::open(p).await.ok()),
|
||||||
Some(p) => Outcome::from_or_forward(req, data, NamedFile::open(p).await.ok()),
|
None => Outcome::forward(data),
|
||||||
None => Outcome::forward(data),
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub fn _catch(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
|
||||||
let status_code = status.0.code;
|
let status_code = status.0.code;
|
||||||
|
|
||||||
// Variables names we'll use and reuse.
|
// Variables names we'll use and reuse.
|
||||||
define_vars_and_mods!(req, catcher, _Box, Request, Response, ErrorHandlerFuture);
|
define_vars_and_mods!(req, catcher, _Box, Request, Response, CatcherFuture);
|
||||||
|
|
||||||
// Determine the number of parameters that will be passed in.
|
// Determine the number of parameters that will be passed in.
|
||||||
let (_fn_sig, inputs) = match catch.function.sig.inputs.len() {
|
let (_fn_sig, inputs) = match catch.function.sig.inputs.len() {
|
||||||
|
@ -96,7 +96,7 @@ pub fn _catch(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
|
||||||
|
|
||||||
/// Rocket code generated wrapping catch function.
|
/// Rocket code generated wrapping catch function.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#vis fn #generated_fn_name<'_b>(#req: &'_b #Request) -> #ErrorHandlerFuture<'_b> {
|
#vis fn #generated_fn_name<'_b>(#req: &'_b #Request) -> #CatcherFuture<'_b> {
|
||||||
#_Box::pin(async move {
|
#_Box::pin(async move {
|
||||||
let __response = #catcher_response;
|
let __response = #catcher_response;
|
||||||
#Response::build()
|
#Response::build()
|
||||||
|
|
|
@ -96,7 +96,7 @@ vars_and_mods! {
|
||||||
StaticRouteInfo => rocket::StaticRouteInfo,
|
StaticRouteInfo => rocket::StaticRouteInfo,
|
||||||
SmallVec => rocket::http::private::SmallVec,
|
SmallVec => rocket::http::private::SmallVec,
|
||||||
HandlerFuture => rocket::handler::HandlerFuture,
|
HandlerFuture => rocket::handler::HandlerFuture,
|
||||||
ErrorHandlerFuture => rocket::handler::ErrorHandlerFuture,
|
CatcherFuture => rocket::handler::CatcherFuture,
|
||||||
_Option => ::std::option::Option,
|
_Option => ::std::option::Option,
|
||||||
_Result => ::std::result::Result,
|
_Result => ::std::result::Result,
|
||||||
_Some => ::std::option::Option::Some,
|
_Some => ::std::option::Option::Some,
|
||||||
|
|
|
@ -77,17 +77,17 @@ impl Catcher {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # #![allow(unused_variables)]
|
/// # #![allow(unused_variables)]
|
||||||
/// use rocket::{Catcher, Request};
|
/// use rocket::{Catcher, Request};
|
||||||
/// use rocket::handler::ErrorHandlerFuture;
|
/// use rocket::handler::CatcherFuture;
|
||||||
/// use rocket::response::{Result, Responder};
|
/// use rocket::response::{Result, Responder};
|
||||||
/// use rocket::response::status::Custom;
|
/// use rocket::response::status::Custom;
|
||||||
/// use rocket::http::Status;
|
/// use rocket::http::Status;
|
||||||
///
|
///
|
||||||
/// fn handle_404<'r>(req: &'r Request) -> ErrorHandlerFuture<'r> {
|
/// fn handle_404<'r>(req: &'r Request) -> CatcherFuture<'r> {
|
||||||
/// let res = Custom(Status::NotFound, format!("404: {}", req.uri()));
|
/// let res = Custom(Status::NotFound, format!("404: {}", req.uri()));
|
||||||
/// Box::pin(async move { res.respond_to(req) })
|
/// Box::pin(async move { res.respond_to(req) })
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn handle_500<'r>(req: &'r Request) -> ErrorHandlerFuture<'r> {
|
/// fn handle_500<'r>(req: &'r Request) -> CatcherFuture<'r> {
|
||||||
/// Box::pin(async move{ "Whoops, we messed up!".respond_to(req) })
|
/// Box::pin(async move{ "Whoops, we messed up!".respond_to(req) })
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -153,7 +153,7 @@ macro_rules! default_catchers {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
$(
|
$(
|
||||||
fn $fn_name<'r>(req: &'r Request<'_>) -> crate::handler::ErrorHandlerFuture<'r> {
|
fn $fn_name<'r>(req: &'r Request<'_>) -> crate::handler::CatcherFuture<'r> {
|
||||||
let status = Status::from_code($code).unwrap();
|
let status = Status::from_code($code).unwrap();
|
||||||
let html = content::Html(error_page_template!($code, $name, $description));
|
let html = content::Html(error_page_template!($code, $name, $description));
|
||||||
Box::pin(async move { status::Custom(status, html).respond_to(req) })
|
Box::pin(async move { status::Custom(status, html).respond_to(req) })
|
||||||
|
|
|
@ -25,6 +25,11 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
|
||||||
/// user provided state to make a request handling decision, you should consider
|
/// user provided state to make a request handling decision, you should consider
|
||||||
/// implementing a custom `Handler`.
|
/// implementing a custom `Handler`.
|
||||||
///
|
///
|
||||||
|
/// ## Async Trait
|
||||||
|
///
|
||||||
|
/// [`Handler`] is an _async_ trait. Implementations of `Handler` must be
|
||||||
|
/// decorated with an attribute of `#[rocket::async_trait]`.
|
||||||
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// Say you'd like to write a handler that changes its functionality based on an
|
/// Say you'd like to write a handler that changes its functionality based on an
|
||||||
|
@ -44,18 +49,19 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # #[derive(Copy, Clone)] enum Kind { Simple, Intermediate, Complex, }
|
/// # #[derive(Copy, Clone)] enum Kind { Simple, Intermediate, Complex, }
|
||||||
/// use rocket::{Request, Data, Route, http::Method};
|
/// use rocket::{Request, Data, Route, http::Method};
|
||||||
/// use rocket::handler::{self, Handler, Outcome, HandlerFuture};
|
/// use rocket::handler::{self, Handler, Outcome};
|
||||||
///
|
///
|
||||||
/// #[derive(Clone)]
|
/// #[derive(Clone)]
|
||||||
/// struct CustomHandler(Kind);
|
/// struct CustomHandler(Kind);
|
||||||
///
|
///
|
||||||
|
/// #[rocket::async_trait]
|
||||||
/// impl Handler for CustomHandler {
|
/// impl Handler for CustomHandler {
|
||||||
/// fn handle<'r>(&self, req: &'r Request, data: Data) -> HandlerFuture<'r> {
|
/// async fn handle<'r, 's: 'r>(&'s self, req: &'r Request<'_>, data: Data) -> Outcome<'r> {
|
||||||
/// match self.0 {
|
/// match self.0 {
|
||||||
/// Kind::Simple => Outcome::from(req, "simple"),
|
/// Kind::Simple => Outcome::from(req, "simple"),
|
||||||
/// Kind::Intermediate => Outcome::from(req, "intermediate"),
|
/// Kind::Intermediate => Outcome::from(req, "intermediate"),
|
||||||
/// Kind::Complex => Outcome::from(req, "complex"),
|
/// Kind::Complex => Outcome::from(req, "complex"),
|
||||||
/// }.pin()
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -131,6 +137,7 @@ pub type HandlerFuture<'r> = BoxFuture<'r, Outcome<'r>>;
|
||||||
/// Use this alternative when a single configuration is desired and your custom
|
/// Use this alternative when a single configuration is desired and your custom
|
||||||
/// handler is private to your application. For all other cases, a custom
|
/// handler is private to your application. For all other cases, a custom
|
||||||
/// `Handler` implementation is preferred.
|
/// `Handler` implementation is preferred.
|
||||||
|
#[crate::async_trait]
|
||||||
pub trait Handler: Cloneable + Send + Sync + 'static {
|
pub trait Handler: Cloneable + Send + Sync + 'static {
|
||||||
/// Called by Rocket when a `Request` with its associated `Data` should be
|
/// Called by Rocket when a `Request` with its associated `Data` should be
|
||||||
/// handled by this handler.
|
/// handled by this handler.
|
||||||
|
@ -142,7 +149,7 @@ pub trait Handler: Cloneable + Send + Sync + 'static {
|
||||||
/// generate a response. Otherwise, if the return value is `Forward(Data)`,
|
/// generate a response. Otherwise, if the return value is `Forward(Data)`,
|
||||||
/// the next matching route is attempted. If there are no other matching
|
/// the next matching route is attempted. If there are no other matching
|
||||||
/// routes, the `404` error catcher is invoked.
|
/// routes, the `404` error catcher is invoked.
|
||||||
fn handle<'r, 's: 'r>(&'s self, request: &'r Request<'_>, data: Data) -> HandlerFuture<'r>;
|
async fn handle<'r, 's: 'r>(&'s self, request: &'r Request<'_>, data: Data) -> Outcome<'r>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unfortunate but necessary hack to be able to clone a `Box<Handler>`.
|
/// Unfortunate but necessary hack to be able to clone a `Box<Handler>`.
|
||||||
|
@ -169,20 +176,21 @@ impl Clone for Box<dyn Handler> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[crate::async_trait]
|
||||||
impl<F: Clone + Sync + Send + 'static> Handler for F
|
impl<F: Clone + Sync + Send + 'static> Handler for F
|
||||||
where for<'r> F: Fn(&'r Request<'_>, Data) -> HandlerFuture<'r>
|
where for<'x> F: Fn(&'x Request<'_>, Data) -> HandlerFuture<'x>
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn handle<'r, 's: 'r>(&'s self, req: &'r Request<'_>, data: Data) -> HandlerFuture<'r> {
|
async fn handle<'r, 's: 'r>(&'s self, req: &'r Request<'_>, data: Data) -> Outcome<'r> {
|
||||||
self(req, data)
|
self(req, data).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of an error handler.
|
/// The type of an error handler.
|
||||||
pub type ErrorHandler = for<'r> fn(&'r Request<'_>) -> ErrorHandlerFuture<'r>;
|
pub type ErrorHandler = for<'r> fn(&'r Request<'_>) -> CatcherFuture<'r>;
|
||||||
|
|
||||||
/// Type type of `Future` returned by an error handler.
|
/// Type type of `Future` returned by an error handler.
|
||||||
pub type ErrorHandlerFuture<'r> = BoxFuture<'r, response::Result<'r>>;
|
pub type CatcherFuture<'r> = BoxFuture<'r, response::Result<'r>>;
|
||||||
|
|
||||||
impl<'r, 'o: 'r> Outcome<'o> {
|
impl<'r, 'o: 'r> Outcome<'o> {
|
||||||
/// Return the `Outcome` of response to `req` from `responder`.
|
/// Return the `Outcome` of response to `req` from `responder`.
|
||||||
|
|
|
@ -674,7 +674,7 @@ impl Rocket {
|
||||||
/// use rocket::http::Method::*;
|
/// use rocket::http::Method::*;
|
||||||
///
|
///
|
||||||
/// fn hi<'r>(req: &'r Request, _: Data) -> HandlerFuture<'r> {
|
/// fn hi<'r>(req: &'r Request, _: Data) -> HandlerFuture<'r> {
|
||||||
/// Outcome::from(req, "Hello!")
|
/// Outcome::from(req, "Hello!").pin()
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let _ = async { // We don't actually want to launch the server in an example.
|
/// # let _ = async { // We don't actually want to launch the server in an example.
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl Route {
|
||||||
/// # use rocket::{Request, Data};
|
/// # use rocket::{Request, Data};
|
||||||
/// # use rocket::handler::{Outcome, HandlerFuture};
|
/// # use rocket::handler::{Outcome, HandlerFuture};
|
||||||
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
||||||
/// # Outcome::from(request, "Hello, world!")
|
/// # Outcome::from(request, "Hello, world!").pin()
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// // this is rank -6 (static path, ~static query)
|
/// // this is rank -6 (static path, ~static query)
|
||||||
|
@ -160,7 +160,7 @@ impl Route {
|
||||||
/// # use rocket::{Request, Data};
|
/// # use rocket::{Request, Data};
|
||||||
/// # use rocket::handler::{Outcome, HandlerFuture};
|
/// # use rocket::handler::{Outcome, HandlerFuture};
|
||||||
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
||||||
/// # Outcome::from(request, "Hello, world!")
|
/// # Outcome::from(request, "Hello, world!").pin()
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// // this is a rank 1 route matching requests to `GET /`
|
/// // this is a rank 1 route matching requests to `GET /`
|
||||||
|
@ -211,7 +211,7 @@ impl Route {
|
||||||
/// # use rocket::handler::{Outcome, HandlerFuture};
|
/// # use rocket::handler::{Outcome, HandlerFuture};
|
||||||
/// #
|
/// #
|
||||||
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
||||||
/// # Outcome::from(request, "Hello, world!")
|
/// # Outcome::from(request, "Hello, world!").pin()
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// let mut index = Route::new(Method::Get, "/", handler);
|
/// let mut index = Route::new(Method::Get, "/", handler);
|
||||||
|
@ -245,7 +245,7 @@ impl Route {
|
||||||
/// # use rocket::handler::{Outcome, HandlerFuture};
|
/// # use rocket::handler::{Outcome, HandlerFuture};
|
||||||
/// #
|
/// #
|
||||||
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
/// # fn handler<'r>(request: &'r Request, _data: Data) -> HandlerFuture<'r> {
|
||||||
/// # Outcome::from(request, "Hello, world!")
|
/// # Outcome::from(request, "Hello, world!").pin()
|
||||||
/// # }
|
/// # }
|
||||||
///
|
///
|
||||||
/// let mut index = Route::new(Method::Get, "/", handler);
|
/// let mut index = Route::new(Method::Get, "/", handler);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::env;
|
||||||
use rocket::{Request, Handler, Route, Data, Catcher, try_outcome};
|
use rocket::{Request, Handler, Route, Data, Catcher, try_outcome};
|
||||||
use rocket::http::{Status, RawStr};
|
use rocket::http::{Status, RawStr};
|
||||||
use rocket::response::{Responder, status::Custom};
|
use rocket::response::{Responder, status::Custom};
|
||||||
use rocket::handler::{Outcome, HandlerFuture, ErrorHandlerFuture};
|
use rocket::handler::{Outcome, HandlerFuture, CatcherFuture};
|
||||||
use rocket::outcome::IntoOutcome;
|
use rocket::outcome::IntoOutcome;
|
||||||
use rocket::http::Method::*;
|
use rocket::http::Method::*;
|
||||||
use rocket::tokio::fs::File;
|
use rocket::tokio::fs::File;
|
||||||
|
@ -66,7 +66,7 @@ fn get_upload<'r>(req: &'r Request, _: Data) -> HandlerFuture<'r> {
|
||||||
Outcome::from(req, std::fs::File::open(env::temp_dir().join("upload.txt")).ok()).pin()
|
Outcome::from(req, std::fs::File::open(env::temp_dir().join("upload.txt")).ok()).pin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not_found_handler<'r>(req: &'r Request) -> ErrorHandlerFuture<'r> {
|
fn not_found_handler<'r>(req: &'r Request) -> CatcherFuture<'r> {
|
||||||
let res = Custom(Status::NotFound, format!("Couldn't find: {}", req.uri()));
|
let res = Custom(Status::NotFound, format!("Couldn't find: {}", req.uri()));
|
||||||
Box::pin(async move { res.respond_to(req) })
|
Box::pin(async move { res.respond_to(req) })
|
||||||
}
|
}
|
||||||
|
@ -82,17 +82,17 @@ impl CustomHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Will this work?
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
impl Handler for CustomHandler {
|
impl Handler for CustomHandler {
|
||||||
fn handle<'r>(&self, req: &'r Request, data: Data) -> HandlerFuture<'r> {
|
async fn handle<'r, 's: 'r>(&'s self, req: &'r Request<'_>, data: Data) -> Outcome<'r> {
|
||||||
let self_data = self.data;
|
let self_data = self.data;
|
||||||
let id_outcome = req.get_param::<&RawStr>(0)
|
let id = req.get_param::<&RawStr>(0)
|
||||||
.and_then(|res| res.ok())
|
.and_then(|res| res.ok())
|
||||||
.or_forward(data);
|
.or_forward(data);
|
||||||
|
|
||||||
Box::pin(async move {
|
Outcome::from(req, format!("{} - {}", self_data, try_outcome!(id)))
|
||||||
let id = try_outcome!(id_outcome);
|
|
||||||
Outcome::from(req, format!("{} - {}", self_data, id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue