rocket/request/
from_request.rs

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