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<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<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}