rocket/request/
from_request.rs

1use std::convert::Infallible;
2use std::fmt::Debug;
3use std::net::{IpAddr, SocketAddr};
4
5use crate::{Request, Route};
6use crate::outcome::{self, Outcome::*};
7
8use crate::http::uri::{Host, Origin};
9use crate::http::{Status, ContentType, Accept, Method, CookieJar};
10
11/// Type alias for the `Outcome` of a `FromRequest` conversion.
12pub type Outcome<S, E> = outcome::Outcome<S, (Status, E), Status>;
13
14/// Trait implemented by request guards to derive a value from incoming
15/// requests.
16///
17/// # Request Guards
18///
19/// A request guard is a type that represents an arbitrary validation policy.
20/// The validation policy is implemented through `FromRequest`. In other words,
21/// every type that implements `FromRequest` is a request guard.
22///
23/// Request guards appear as inputs to handlers. An arbitrary number of request
24/// guards can appear as arguments in a route handler. Rocket will automatically
25/// invoke the `FromRequest` implementation for request guards before calling
26/// the handler. Rocket only dispatches requests to a handler when all of its
27/// guards pass.
28///
29/// ## Async Trait
30///
31/// [`FromRequest`] is an _async_ trait. Implementations of `FromRequest` must
32/// be decorated with an attribute of `#[rocket::async_trait]`:
33///
34/// ```rust
35/// use rocket::request::{self, Request, FromRequest};
36/// # struct MyType;
37/// # type MyError = String;
38///
39/// #[rocket::async_trait]
40/// impl<'r> FromRequest<'r> for MyType {
41///     type Error = MyError;
42///
43///     async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
44///         /* .. */
45///         # unimplemented!()
46///     }
47/// }
48/// ```
49///
50/// ## Example
51///
52/// The following dummy handler makes use of three request guards, `A`, `B`, and
53/// `C`. An input type can be identified as a request guard if it is not named
54/// in the route attribute. This is why, for instance, `param` is not a request
55/// guard.
56///
57/// ```rust
58/// # #[macro_use] extern crate rocket;
59/// # use rocket::http::Method;
60/// # type A = Method; type B = Method; type C = Method; type T = ();
61/// #[get("/<param>")]
62/// fn index(param: isize, a: A, b: B, c: C) -> T { /* ... */ }
63/// # fn main() {}
64/// ```
65///
66/// Request guards always fire in left-to-right declaration order. In the
67/// example above, the order is `a` followed by `b` followed by `c`. Errors are
68/// short-circuiting; if one guard errors, the remaining are not attempted.
69///
70/// # Outcomes
71///
72/// The returned [`Outcome`] of a `from_request` call determines how the
73/// incoming request will be processed.
74///
75/// * **Success**(S)
76///
77///   If the `Outcome` is [`Success`], then the `Success` value will be used as
78///   the value for the corresponding parameter.  As long as all other guards
79///   succeed, the request will be handled.
80///
81/// * **Error**(Status, E)
82///
83///   If the `Outcome` is [`Error`], the request will fail with the given
84///   status code and error. The designated error [`Catcher`](crate::Catcher)
85///   will be used to respond to the request. Note that users can request types
86///   of `Result<S, E>` and `Option<S>` to catch `Error`s and retrieve the
87///   error value.
88///
89/// * **Forward**(Status)
90///
91///   If the `Outcome` is [`Forward`], the request will be forwarded to the next
92///   matching route until either one succeeds or there are no further matching
93///   routes to attempt. In the latter case, the request will be sent to the
94///   [`Catcher`](crate::Catcher) for the designated `Status`. Note that users
95///   can request an `Option<S>` to catch `Forward`s.
96///
97/// # Provided Implementations
98///
99/// Rocket implements `FromRequest` for several built-in types. Their behavior
100/// is documented here.
101///
102///   * **Method**
103///
104///     Extracts the [`Method`] from the incoming request.
105///
106///     _This implementation always returns successfully._
107///
108///   * **&Origin**
109///
110///     Extracts the [`Origin`] URI from the incoming request.
111///
112///     _This implementation always returns successfully._
113///
114///   * **&Host**
115///
116///     Extracts the [`Host`] from the incoming request, if it exists. See
117///     [`Request::host()`] for details. If it does not exist, the request is
118///     forwarded with a 500 Internal Server Error status.
119///
120///   * **&Route**
121///
122///     Extracts the [`Route`] from the request if one is available. When used
123///     as a request guard in a route handler, this will always succeed. Outside
124///     of a route handler, a route may not be available, and the request is
125///     forwarded with a 500 Internal Server Error status.
126///
127///     For more information on when an `&Route` is available, see
128///     [`Request::route()`].
129///
130///   * **&CookieJar**
131///
132///     Returns a borrow to the [`CookieJar`] in the incoming request. Note that
133///     `CookieJar` implements internal mutability, so a handle to a `CookieJar`
134///     allows you to get _and_ set cookies in the request.
135///
136///     _This implementation always returns successfully._
137///
138///   * **&[`Config`]**
139///
140///     Extracts the application [`Config`].
141///
142///     _This implementation always returns successfully._
143///
144///   * **&ContentType**
145///
146///     Extracts the [`ContentType`] header from the incoming request via
147///     [`Request::content_type()`]. If the request didn't specify a
148///     Content-Type, the request is forwarded with a 500 Internal Server Error
149///     status.
150///
151///   * **&Accept**
152///
153///     Extracts the [`Accept`] header from the incoming request via
154///     [`Request::accept()`]. If the request didn't specify an `Accept`, the
155///     request is forwarded with a 500 Internal Server Error status.
156///
157///   * ***IpAddr**
158///
159///     Extracts the client ip address of the incoming request as an [`IpAddr`]
160///     via [`Request::client_ip()`]. If the client's IP address is not known,
161///     the request is forwarded with a 500 Internal Server Error status.
162///
163///   * **SocketAddr**
164///
165///     Extracts the remote address of the incoming request as a [`SocketAddr`]
166///     via [`Request::remote()`]. If the remote address is not known, the
167///     request is forwarded with a 500 Internal Server Error status.
168///
169///   * **Option&lt;T>** _where_ **T: FromRequest**
170///
171///     The type `T` is derived from the incoming request using `T`'s
172///     `FromRequest` implementation. If the derivation is a `Success`, the
173///     derived value is returned in `Some`. Otherwise, a `None` is returned.
174///
175///     _This implementation always returns successfully._
176///
177///   * **Result&lt;T, T::Error>** _where_ **T: FromRequest**
178///
179///     The type `T` is derived from the incoming request using `T`'s
180///     `FromRequest` implementation. If derivation is a `Success`, the value is
181///     returned in `Ok`. If the derivation is an `Error`, the error value is
182///     returned in `Err`. If the derivation is a `Forward`, the request is
183///     forwarded with the same status code as the original forward.
184///
185/// [`Config`]: crate::config::Config
186///
187/// # Example
188///
189/// Imagine you're running an authenticated API service that requires that some
190/// requests be sent along with a valid API key in a header field. You want to
191/// ensure that the handlers corresponding to these requests don't get called
192/// unless there is an API key in the request and the key is valid. The
193/// following example implements this using an `ApiKey` type and a `FromRequest`
194/// implementation for that type. The `ApiKey` type is then used in the
195/// `sensitive` handler.
196///
197/// ```rust
198/// # #[macro_use] extern crate rocket;
199/// #
200/// use rocket::http::Status;
201/// use rocket::request::{self, Outcome, Request, FromRequest};
202///
203/// struct ApiKey<'r>(&'r str);
204///
205/// #[derive(Debug)]
206/// enum ApiKeyError {
207///     Missing,
208///     Invalid,
209/// }
210///
211/// #[rocket::async_trait]
212/// impl<'r> FromRequest<'r> for ApiKey<'r> {
213///     type Error = ApiKeyError;
214///
215///     async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
216///         /// Returns true if `key` is a valid API key string.
217///         fn is_valid(key: &str) -> bool {
218///             key == "valid_api_key"
219///         }
220///
221///         match req.headers().get_one("x-api-key") {
222///             None => Outcome::Error((Status::BadRequest, ApiKeyError::Missing)),
223///             Some(key) if is_valid(key) => Outcome::Success(ApiKey(key)),
224///             Some(_) => Outcome::Error((Status::BadRequest, ApiKeyError::Invalid)),
225///         }
226///     }
227/// }
228///
229/// #[get("/sensitive")]
230/// fn sensitive(key: ApiKey<'_>) -> &'static str {
231///     "Sensitive data."
232/// }
233/// ```
234///
235/// # Request-Local State
236///
237/// Request guards that perform expensive operations, such as those that query a
238/// database or an external service, should use the [request-local state] cache
239/// to store results if they might be invoked multiple times during the routing
240/// of a single request.
241///
242/// For example, consider a pair of `User` and `Admin` guards and a pair of
243/// routes (`admin_dashboard` and `user_dashboard`):
244///
245/// ```rust
246/// # #[macro_use] extern crate rocket;
247/// # #[cfg(feature = "secrets")] mod wrapper {
248/// # use rocket::outcome::{IntoOutcome, try_outcome};
249/// # use rocket::request::{self, Outcome, FromRequest, Request};
250/// # use rocket::http::Status;
251/// # struct User { id: String, is_admin: bool }
252/// # struct Database;
253/// # impl Database {
254/// #     fn get_user(&self, id: String) -> Result<User, ()> {
255/// #         Ok(User { id, is_admin: false })
256/// #     }
257/// # }
258/// # #[rocket::async_trait]
259/// # impl<'r> FromRequest<'r> for Database {
260/// #     type Error = ();
261/// #     async fn from_request(request: &'r Request<'_>) -> Outcome<Database, ()> {
262/// #         Outcome::Success(Database)
263/// #     }
264/// # }
265/// #
266/// # struct Admin { user: User }
267/// #
268/// #[rocket::async_trait]
269/// impl<'r> FromRequest<'r> for User {
270///     type Error = ();
271///
272///     async fn from_request(request: &'r Request<'_>) -> Outcome<User, ()> {
273///         let db = try_outcome!(request.guard::<Database>().await);
274///         request.cookies()
275///             .get_private("user_id")
276///             .and_then(|cookie| cookie.value().parse().ok())
277///             .and_then(|id| db.get_user(id).ok())
278///             .or_forward(Status::Unauthorized)
279///     }
280/// }
281///
282/// #[rocket::async_trait]
283/// impl<'r> FromRequest<'r> for Admin {
284///     type Error = ();
285///
286///     async fn from_request(request: &'r Request<'_>) -> Outcome<Admin, ()> {
287///         // This will unconditionally query the database!
288///         let user = try_outcome!(request.guard::<User>().await);
289///         if user.is_admin {
290///             Outcome::Success(Admin { user })
291///         } else {
292///             Outcome::Forward(Status::Unauthorized)
293///         }
294///     }
295/// }
296///
297/// #[get("/dashboard")]
298/// fn admin_dashboard(admin: Admin) { }
299///
300/// #[get("/dashboard", rank = 2)]
301/// fn user_dashboard(user: User) { }
302/// # } // end of cfg wrapper
303/// ```
304///
305/// When a non-admin user is logged in, the database will be queried twice: once
306/// via the `Admin` guard invoking the `User` guard, and a second time via the
307/// `User` guard directly. For cases like these, request-local state should be
308/// used, as illustrated below:
309///
310/// ```rust
311/// # #[macro_use] extern crate rocket;
312/// # #[cfg(feature = "secrets")] mod wrapper {
313/// # use rocket::outcome::{IntoOutcome, try_outcome};
314/// # use rocket::request::{self, Outcome, FromRequest, Request};
315/// # use rocket::http::Status;
316/// # struct User { id: String, is_admin: bool }
317/// # struct Database;
318/// # impl Database {
319/// #     fn get_user(&self, id: String) -> Result<User, ()> {
320/// #         Ok(User { id, is_admin: false })
321/// #     }
322/// # }
323/// # #[rocket::async_trait]
324/// # impl<'r> FromRequest<'r> for Database {
325/// #     type Error = ();
326/// #     async fn from_request(request: &'r Request<'_>) -> Outcome<Database, ()> {
327/// #         Outcome::Success(Database)
328/// #     }
329/// # }
330/// #
331/// # struct Admin<'a> { user: &'a User }
332/// #
333/// #[rocket::async_trait]
334/// impl<'r> FromRequest<'r> for &'r User {
335///     type Error = std::convert::Infallible;
336///
337///     async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
338///         // This closure will execute at most once per request, regardless of
339///         // the number of times the `User` guard is executed.
340///         let user_result = request.local_cache_async(async {
341///             let db = request.guard::<Database>().await.succeeded()?;
342///             request.cookies()
343///                 .get_private("user_id")
344///                 .and_then(|cookie| cookie.value().parse().ok())
345///                 .and_then(|id| db.get_user(id).ok())
346///         }).await;
347///
348///         user_result.as_ref().or_forward(Status::Unauthorized)
349///     }
350/// }
351///
352/// #[rocket::async_trait]
353/// impl<'r> FromRequest<'r> for Admin<'r> {
354///     type Error = std::convert::Infallible;
355///
356///     async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
357///         let user = try_outcome!(request.guard::<&User>().await);
358///         if user.is_admin {
359///             Outcome::Success(Admin { user })
360///         } else {
361///             Outcome::Forward(Status::Unauthorized)
362///         }
363///     }
364/// }
365/// # } // end of cfg wrapper
366/// ```
367///
368/// Notice that these request guards provide access to *borrowed* data (`&'a
369/// User` and `Admin<'a>`) as the data is now owned by the request's cache.
370///
371/// [request-local state]: https://rocket.rs/v0.5/guide/state/#request-local-state
372#[crate::async_trait]
373pub trait FromRequest<'r>: Sized {
374    /// The associated error to be returned if derivation fails.
375    type Error: Debug;
376
377    /// Derives an instance of `Self` from the incoming request metadata.
378    ///
379    /// If the derivation is successful, an outcome of `Success` is returned. If
380    /// the derivation fails in an unrecoverable fashion, `Error` is returned.
381    /// `Forward` is returned to indicate that the request should be forwarded
382    /// to other matching routes, if any.
383    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error>;
384}
385
386#[crate::async_trait]
387impl<'r> FromRequest<'r> for Method {
388    type Error = Infallible;
389
390    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
391        Success(request.method())
392    }
393}
394
395#[crate::async_trait]
396impl<'r> FromRequest<'r> for &'r Origin<'r> {
397    type Error = Infallible;
398
399    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
400        Success(request.uri())
401    }
402}
403
404#[crate::async_trait]
405impl<'r> FromRequest<'r> for &'r Host<'r> {
406    type Error = Infallible;
407
408    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
409        match request.host() {
410            Some(host) => Success(host),
411            None => Forward(Status::InternalServerError)
412        }
413    }
414}
415
416#[crate::async_trait]
417impl<'r> FromRequest<'r> for &'r Route {
418    type Error = Infallible;
419
420    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
421        match request.route() {
422            Some(route) => Success(route),
423            None => Forward(Status::InternalServerError)
424        }
425    }
426}
427
428#[crate::async_trait]
429impl<'r> FromRequest<'r> for &'r CookieJar<'r> {
430    type Error = Infallible;
431
432    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
433        Success(request.cookies())
434    }
435}
436
437#[crate::async_trait]
438impl<'r> FromRequest<'r> for &'r Accept {
439    type Error = Infallible;
440
441    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
442        match request.accept() {
443            Some(accept) => Success(accept),
444            None => Forward(Status::InternalServerError)
445        }
446    }
447}
448
449#[crate::async_trait]
450impl<'r> FromRequest<'r> for &'r ContentType {
451    type Error = Infallible;
452
453    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
454        match request.content_type() {
455            Some(content_type) => Success(content_type),
456            None => Forward(Status::InternalServerError)
457        }
458    }
459}
460
461#[crate::async_trait]
462impl<'r> FromRequest<'r> for IpAddr {
463    type Error = Infallible;
464
465    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
466        match request.client_ip() {
467            Some(addr) => Success(addr),
468            None => Forward(Status::InternalServerError)
469        }
470    }
471}
472
473#[crate::async_trait]
474impl<'r> FromRequest<'r> for SocketAddr {
475    type Error = Infallible;
476
477    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
478        match request.remote() {
479            Some(addr) => Success(addr),
480            None => Forward(Status::InternalServerError)
481        }
482    }
483}
484
485#[crate::async_trait]
486impl<'r, T: FromRequest<'r>> FromRequest<'r> for Result<T, T::Error> {
487    type Error = Infallible;
488
489    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
490        match T::from_request(request).await {
491            Success(val) => Success(Ok(val)),
492            Error((_, e)) => Success(Err(e)),
493            Forward(status) => Forward(status),
494        }
495    }
496}
497
498#[crate::async_trait]
499impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option<T> {
500    type Error = Infallible;
501
502    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
503        match T::from_request(request).await {
504            Success(val) => Success(Some(val)),
505            Error(_) | Forward(_) => Success(None),
506        }
507    }
508}
509
510#[crate::async_trait]
511impl<'r, T: FromRequest<'r>> FromRequest<'r> for Outcome<T, T::Error> {
512    type Error = Infallible;
513
514    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Infallible> {
515        Success(T::from_request(request).await)
516    }
517}