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