2016-08-08 10:10:23 +00:00
|
|
|
use std::fmt::Debug;
|
2016-10-04 00:09:13 +00:00
|
|
|
|
2016-10-25 11:03:50 +00:00
|
|
|
use outcome::{self, IntoOutcome};
|
2016-10-04 00:09:13 +00:00
|
|
|
use request::Request;
|
2016-10-25 09:17:49 +00:00
|
|
|
use outcome::Outcome::*;
|
2016-12-15 08:47:31 +00:00
|
|
|
use http::{Status, ContentType, Method, Cookies};
|
2016-10-14 01:39:23 +00:00
|
|
|
|
2016-10-21 09:56:57 +00:00
|
|
|
/// Type alias for the `Outcome` of a `FromRequest` conversion.
|
2016-12-15 08:47:31 +00:00
|
|
|
pub type Outcome<S, E> = outcome::Outcome<S, (Status, E), ()>;
|
2016-08-08 10:10:23 +00:00
|
|
|
|
2016-12-15 08:47:31 +00:00
|
|
|
impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
|
2016-11-06 16:07:47 +00:00
|
|
|
fn into_outcome(self) -> Outcome<S, E> {
|
2016-10-25 11:03:50 +00:00
|
|
|
match self {
|
|
|
|
Ok(val) => Success(val),
|
2016-12-15 08:47:31 +00:00
|
|
|
Err(val) => Failure((Status::BadRequest, val))
|
2016-10-25 11:03:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-06 16:07:47 +00:00
|
|
|
/// Trait used to derive an object from incoming request metadata.
|
|
|
|
///
|
2016-11-21 08:45:44 +00:00
|
|
|
/// An arbitrary number of types that implement this trait can appear as
|
2016-11-06 16:07:47 +00:00
|
|
|
/// parameters in a route handler, as illustrated below:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// #[get("/")]
|
|
|
|
/// fn index(a: A, b: B, c: C) -> ... { ... }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// In this example, `A`, `B`, and `C` can be any types that implements
|
|
|
|
/// `FromRequest`. There can be any number of `FromRequest` types in the
|
|
|
|
/// function signature. Note that unlike every other derived object in Rocket,
|
|
|
|
/// `FromRequest` parameter names do not need to be declared in the route
|
|
|
|
/// attribute.
|
|
|
|
///
|
|
|
|
/// Derivation of `FromRequest` arguments is always attemped in left-to-right
|
|
|
|
/// declaration order. In the example above, for instance, the order will be `a`
|
|
|
|
/// followed by `b` followed by `c`. If a deriviation fails, the following
|
|
|
|
/// aren't attempted.
|
|
|
|
///
|
|
|
|
/// # Outcomes
|
|
|
|
///
|
|
|
|
/// The returned [Outcome](/rocket/outcome/index.html) of a `from_request` call
|
|
|
|
/// determines how the incoming request will be processed.
|
|
|
|
///
|
|
|
|
/// * **Success**(S)
|
|
|
|
///
|
|
|
|
/// If the `Outcome` is `Success`, then the `Success` value will be used as
|
|
|
|
/// the value for the corresponding parameter. As long as all other parsed
|
|
|
|
/// types succeed, the request will be handled.
|
|
|
|
///
|
2016-12-15 08:47:31 +00:00
|
|
|
/// * **Failure**(Status, E)
|
2016-11-06 16:07:47 +00:00
|
|
|
///
|
|
|
|
/// If the `Outcome` is `Failure`, the request will fail with the given status
|
|
|
|
/// code and error. The designated error
|
|
|
|
/// [Catcher](/rocket/struct.Catcher.html) will be used to respond to the
|
|
|
|
/// request. Note that users can request types of `Result<S, E>` and
|
|
|
|
/// `Option<S>` to catch `Failure`s and retrieve the error value.
|
|
|
|
///
|
|
|
|
/// * **Forward**
|
|
|
|
///
|
|
|
|
/// If the `Outcome` is `Forward`, the request will be forwarded to the next
|
|
|
|
/// matching request. Note that users can request an `Option<S>` to catch
|
|
|
|
/// `Forward`s.
|
2016-11-21 08:45:44 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// Imagine you're running an authenticated API service that requires that some
|
|
|
|
/// requests be sent along with a valid API key in a header field. You want to
|
|
|
|
/// ensure that the handlers corresponding to these requests don't get called
|
|
|
|
/// unless there is an API key in the request and the key is valid. The
|
|
|
|
/// following example implements this using an `APIKey` type and a `FromRequest`
|
|
|
|
/// implementation for that type in the `senstive` handler:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![feature(plugin)]
|
|
|
|
/// # #![plugin(rocket_codegen)]
|
|
|
|
/// # extern crate rocket;
|
|
|
|
/// #
|
|
|
|
/// use rocket::Outcome;
|
2016-12-15 08:47:31 +00:00
|
|
|
/// use rocket::http::Status;
|
2016-11-21 08:45:44 +00:00
|
|
|
/// use rocket::request::{self, Request, FromRequest};
|
|
|
|
///
|
|
|
|
/// struct APIKey(String);
|
|
|
|
///
|
|
|
|
/// /// Returns true if `key` is a valid API key string.
|
|
|
|
/// fn is_valid(key: &str) -> bool {
|
|
|
|
/// key == "valid_api_key"
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl<'r> FromRequest<'r> for APIKey {
|
|
|
|
/// type Error = ();
|
|
|
|
/// fn from_request(request: &'r Request) -> request::Outcome<APIKey, ()> {
|
|
|
|
/// if let Some(keys) = request.headers().get_raw("x-api-key") {
|
|
|
|
/// if keys.len() != 1 {
|
2016-12-15 08:47:31 +00:00
|
|
|
/// return Outcome::Failure((Status::BadRequest, ()));
|
2016-11-21 08:45:44 +00:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// if let Ok(key) = String::from_utf8(keys[0].clone()) {
|
|
|
|
/// if is_valid(&key) {
|
|
|
|
/// return Outcome::Success(APIKey(key));
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// Outcome::Forward(())
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[get("/sensitive")]
|
|
|
|
/// fn sensitive(key: APIKey) -> &'static str {
|
|
|
|
/// "Sensitive data."
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
2016-10-08 06:20:49 +00:00
|
|
|
pub trait FromRequest<'r>: Sized {
|
2016-11-06 16:07:47 +00:00
|
|
|
/// The associated error to be returned when derivation fails.
|
2016-08-08 10:10:23 +00:00
|
|
|
type Error: Debug;
|
|
|
|
|
2016-11-06 16:07:47 +00:00
|
|
|
/// Derives an instance of `Self` from the incoming request metadata.
|
|
|
|
///
|
|
|
|
/// If the derivation is successful, an outcome of `Success` is returned. If
|
|
|
|
/// the derivation fails in an unrecoverable fashion, `Failure` is returned.
|
|
|
|
/// `Forward` is returned to indicate that the request should be forwarded
|
|
|
|
/// to other matching routes, if any.
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error>;
|
2016-08-08 10:10:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-08 06:20:49 +00:00
|
|
|
impl<'r> FromRequest<'r> for &'r Request {
|
2016-08-08 10:10:23 +00:00
|
|
|
type Error = ();
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error> {
|
|
|
|
Success(request)
|
2016-08-08 10:10:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-08 06:20:49 +00:00
|
|
|
impl<'r> FromRequest<'r> for Method {
|
2016-08-27 12:10:29 +00:00
|
|
|
type Error = ();
|
2016-08-08 10:10:23 +00:00
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error> {
|
|
|
|
Success(request.method)
|
2016-08-08 10:10:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-08 06:20:49 +00:00
|
|
|
impl<'r> FromRequest<'r> for &'r Cookies {
|
2016-08-27 12:10:29 +00:00
|
|
|
type Error = ();
|
2016-10-14 01:39:23 +00:00
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error> {
|
|
|
|
Success(request.cookies())
|
2016-08-08 10:48:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-08 06:20:49 +00:00
|
|
|
impl<'r> FromRequest<'r> for ContentType {
|
2016-08-27 12:10:29 +00:00
|
|
|
type Error = ();
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error> {
|
|
|
|
Success(request.content_type())
|
2016-08-27 12:10:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Result<T, T::Error> {
|
2016-08-08 10:10:23 +00:00
|
|
|
type Error = ();
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error> {
|
2016-10-14 01:39:23 +00:00
|
|
|
match T::from_request(request) {
|
2016-10-25 09:17:49 +00:00
|
|
|
Success(val) => Success(Ok(val)),
|
|
|
|
Failure((_, e)) => Success(Err(e)),
|
|
|
|
Forward(_) => Forward(()),
|
2016-10-14 01:39:23 +00:00
|
|
|
}
|
2016-08-08 10:10:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option<T> {
|
2016-08-08 10:10:23 +00:00
|
|
|
type Error = ();
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
fn from_request(request: &'r Request) -> Outcome<Self, Self::Error> {
|
2016-10-14 01:39:23 +00:00
|
|
|
match T::from_request(request) {
|
2016-10-25 09:17:49 +00:00
|
|
|
Success(val) => Success(Some(val)),
|
|
|
|
Failure(_) => Success(None),
|
|
|
|
Forward(_) => Success(None),
|
2016-10-14 01:39:23 +00:00
|
|
|
}
|
2016-08-08 10:10:23 +00:00
|
|
|
}
|
|
|
|
}
|
2016-10-14 01:39:23 +00:00
|
|
|
|