rocket_community/request/
from_request.rs

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