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