1 //! Request extractors
2 
3 use std::{
4     convert::Infallible,
5     future::Future,
6     pin::Pin,
7     task::{Context, Poll},
8 };
9 
10 use actix_http::http::{Method, Uri};
11 use actix_utils::future::{ok, Ready};
12 use futures_core::ready;
13 
14 use crate::{dev::Payload, Error, HttpRequest};
15 
16 /// Trait implemented by types that can be extracted from request.
17 ///
18 /// Types that implement this trait can be used with `Route` handlers.
19 pub trait FromRequest: Sized {
20     /// Configuration for this extractor.
21     type Config: Default + 'static;
22 
23     /// The associated error which can be returned.
24     type Error: Into<Error>;
25 
26     /// Future that resolves to a Self.
27     type Future: Future<Output = Result<Self, Self::Error>>;
28 
29     /// Create a Self from request parts asynchronously.
from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future30     fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future;
31 
32     /// Create a Self from request head asynchronously.
33     ///
34     /// This method is short for `T::from_request(req, &mut Payload::None)`.
extract(req: &HttpRequest) -> Self::Future35     fn extract(req: &HttpRequest) -> Self::Future {
36         Self::from_request(req, &mut Payload::None)
37     }
38 
39     /// Create and configure config instance.
configure<F>(f: F) -> Self::Config where F: FnOnce(Self::Config) -> Self::Config,40     fn configure<F>(f: F) -> Self::Config
41     where
42         F: FnOnce(Self::Config) -> Self::Config,
43     {
44         f(Self::Config::default())
45     }
46 }
47 
48 /// Optionally extract a field from the request
49 ///
50 /// If the FromRequest for T fails, return None rather than returning an error response
51 ///
52 /// # Examples
53 /// ```
54 /// use actix_web::{web, dev, App, Error, HttpRequest, FromRequest};
55 /// use actix_web::error::ErrorBadRequest;
56 /// use futures_util::future::{ok, err, Ready};
57 /// use serde::Deserialize;
58 /// use rand;
59 ///
60 /// #[derive(Debug, Deserialize)]
61 /// struct Thing {
62 ///     name: String
63 /// }
64 ///
65 /// impl FromRequest for Thing {
66 ///     type Error = Error;
67 ///     type Future = Ready<Result<Self, Self::Error>>;
68 ///     type Config = ();
69 ///
70 ///     fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
71 ///         if rand::random() {
72 ///             ok(Thing { name: "thingy".into() })
73 ///         } else {
74 ///             err(ErrorBadRequest("no luck"))
75 ///         }
76 ///
77 ///     }
78 /// }
79 ///
80 /// /// extract `Thing` from request
81 /// async fn index(supplied_thing: Option<Thing>) -> String {
82 ///     match supplied_thing {
83 ///         // Puns not intended
84 ///         Some(thing) => format!("Got something: {:?}", thing),
85 ///         None => format!("No thing!")
86 ///     }
87 /// }
88 ///
89 /// fn main() {
90 ///     let app = App::new().service(
91 ///         web::resource("/users/:first").route(
92 ///             web::post().to(index))
93 ///     );
94 /// }
95 /// ```
96 impl<T: 'static> FromRequest for Option<T>
97 where
98     T: FromRequest,
99     T::Future: 'static,
100 {
101     type Error = Error;
102     type Future = FromRequestOptFuture<T::Future>;
103     type Config = T::Config;
104 
105     #[inline]
from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future106     fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
107         FromRequestOptFuture {
108             fut: T::from_request(req, payload),
109         }
110     }
111 }
112 
113 #[pin_project::pin_project]
114 pub struct FromRequestOptFuture<Fut> {
115     #[pin]
116     fut: Fut,
117 }
118 
119 impl<Fut, T, E> Future for FromRequestOptFuture<Fut>
120 where
121     Fut: Future<Output = Result<T, E>>,
122     E: Into<Error>,
123 {
124     type Output = Result<Option<T>, Error>;
125 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>126     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
127         let this = self.project();
128         let res = ready!(this.fut.poll(cx));
129         match res {
130             Ok(t) => Poll::Ready(Ok(Some(t))),
131             Err(e) => {
132                 log::debug!("Error for Option<T> extractor: {}", e.into());
133                 Poll::Ready(Ok(None))
134             }
135         }
136     }
137 }
138 
139 /// Optionally extract a field from the request or extract the Error if unsuccessful
140 ///
141 /// If the `FromRequest` for T fails, inject Err into handler rather than returning an error response
142 ///
143 /// # Examples
144 /// ```
145 /// use actix_web::{web, dev, App, Result, Error, HttpRequest, FromRequest};
146 /// use actix_web::error::ErrorBadRequest;
147 /// use futures_util::future::{ok, err, Ready};
148 /// use serde::Deserialize;
149 /// use rand;
150 ///
151 /// #[derive(Debug, Deserialize)]
152 /// struct Thing {
153 ///     name: String
154 /// }
155 ///
156 /// impl FromRequest for Thing {
157 ///     type Error = Error;
158 ///     type Future = Ready<Result<Thing, Error>>;
159 ///     type Config = ();
160 ///
161 ///     fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
162 ///         if rand::random() {
163 ///             ok(Thing { name: "thingy".into() })
164 ///         } else {
165 ///             err(ErrorBadRequest("no luck"))
166 ///         }
167 ///     }
168 /// }
169 ///
170 /// /// extract `Thing` from request
171 /// async fn index(supplied_thing: Result<Thing>) -> String {
172 ///     match supplied_thing {
173 ///         Ok(thing) => format!("Got thing: {:?}", thing),
174 ///         Err(e) => format!("Error extracting thing: {}", e)
175 ///     }
176 /// }
177 ///
178 /// fn main() {
179 ///     let app = App::new().service(
180 ///         web::resource("/users/:first").route(web::post().to(index))
181 ///     );
182 /// }
183 /// ```
184 impl<T> FromRequest for Result<T, T::Error>
185 where
186     T: FromRequest + 'static,
187     T::Error: 'static,
188     T::Future: 'static,
189 {
190     type Error = Error;
191     type Future = FromRequestResFuture<T::Future>;
192     type Config = T::Config;
193 
194     #[inline]
from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future195     fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
196         FromRequestResFuture {
197             fut: T::from_request(req, payload),
198         }
199     }
200 }
201 
202 #[pin_project::pin_project]
203 pub struct FromRequestResFuture<Fut> {
204     #[pin]
205     fut: Fut,
206 }
207 
208 impl<Fut, T, E> Future for FromRequestResFuture<Fut>
209 where
210     Fut: Future<Output = Result<T, E>>,
211 {
212     type Output = Result<Result<T, E>, Error>;
213 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>214     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
215         let this = self.project();
216         let res = ready!(this.fut.poll(cx));
217         Poll::Ready(Ok(res))
218     }
219 }
220 
221 /// Extract the request's URI.
222 ///
223 /// # Examples
224 /// ```
225 /// use actix_web::{http::Uri, web, App, Responder};
226 ///
227 /// async fn handler(uri: Uri) -> impl Responder {
228 ///     format!("Requested path: {}", uri.path())
229 /// }
230 ///
231 /// let app = App::new().default_service(web::to(handler));
232 /// ```
233 impl FromRequest for Uri {
234     type Error = Infallible;
235     type Future = Ready<Result<Self, Self::Error>>;
236     type Config = ();
237 
from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future238     fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
239         ok(req.uri().clone())
240     }
241 }
242 
243 /// Extract the request's method.
244 ///
245 /// # Examples
246 /// ```
247 /// use actix_web::{http::Method, web, App, Responder};
248 ///
249 /// async fn handler(method: Method) -> impl Responder {
250 ///     format!("Request method: {}", method)
251 /// }
252 ///
253 /// let app = App::new().default_service(web::to(handler));
254 /// ```
255 impl FromRequest for Method {
256     type Error = Infallible;
257     type Future = Ready<Result<Self, Self::Error>>;
258     type Config = ();
259 
from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future260     fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
261         ok(req.method().clone())
262     }
263 }
264 
265 #[doc(hidden)]
266 impl FromRequest for () {
267     type Error = Infallible;
268     type Future = Ready<Result<Self, Self::Error>>;
269     type Config = ();
270 
from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future271     fn from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future {
272         ok(())
273     }
274 }
275 
276 macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
277 
278     // This module is a trick to get around the inability of
279     // `macro_rules!` macros to make new idents. We want to make
280     // a new `FutWrapper` struct for each distinct invocation of
281     // this macro. Ideally, we would name it something like
282     // `FutWrapper_$fut_type`, but this can't be done in a macro_rules
283     // macro.
284     //
285     // Instead, we put everything in a module named `$fut_type`, thus allowing
286     // us to use the name `FutWrapper` without worrying about conflicts.
287     // This macro only exists to generate trait impls for tuples - these
288     // are inherently global, so users don't have to care about this
289     // weird trick.
290     #[allow(non_snake_case)]
291     mod $fut_type {
292 
293         // Bring everything into scope, so we don't need
294         // redundant imports
295         use super::*;
296 
297         /// A helper struct to allow us to pin-project through
298         /// to individual fields
299         #[pin_project::pin_project]
300         struct FutWrapper<$($T: FromRequest),+>($(#[pin] $T::Future),+);
301 
302         /// FromRequest implementation for tuple
303         #[doc(hidden)]
304         #[allow(unused_parens)]
305         impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
306         {
307             type Error = Error;
308             type Future = $fut_type<$($T),+>;
309             type Config = ($($T::Config),+);
310 
311             fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
312                 $fut_type {
313                     items: <($(Option<$T>,)+)>::default(),
314                     futs: FutWrapper($($T::from_request(req, payload),)+),
315                 }
316             }
317         }
318 
319         #[doc(hidden)]
320         #[pin_project::pin_project]
321         pub struct $fut_type<$($T: FromRequest),+> {
322             items: ($(Option<$T>,)+),
323             #[pin]
324             futs: FutWrapper<$($T,)+>,
325         }
326 
327         impl<$($T: FromRequest),+> Future for $fut_type<$($T),+>
328         {
329             type Output = Result<($($T,)+), Error>;
330 
331             fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
332                 let mut this = self.project();
333 
334                 let mut ready = true;
335                 $(
336                     if this.items.$n.is_none() {
337                         match this.futs.as_mut().project().$n.poll(cx) {
338                             Poll::Ready(Ok(item)) => {
339                                 this.items.$n = Some(item);
340                             }
341                             Poll::Pending => ready = false,
342                             Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
343                         }
344                     }
345                 )+
346 
347                 if ready {
348                     Poll::Ready(Ok(
349                         ($(this.items.$n.take().unwrap(),)+)
350                     ))
351                 } else {
352                     Poll::Pending
353                 }
354             }
355         }
356     }
357 });
358 
359 #[rustfmt::skip]
360 mod m {
361     use super::*;
362 
363     tuple_from_req!(TupleFromRequest1, (0, A));
364     tuple_from_req!(TupleFromRequest2, (0, A), (1, B));
365     tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));
366     tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
367     tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
368     tuple_from_req!(TupleFromRequest6, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
369     tuple_from_req!(TupleFromRequest7, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
370     tuple_from_req!(TupleFromRequest8, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H));
371     tuple_from_req!(TupleFromRequest9, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I));
372     tuple_from_req!(TupleFromRequest10, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J));
373 }
374 
375 #[cfg(test)]
376 mod tests {
377     use actix_http::http::header;
378     use bytes::Bytes;
379     use serde::Deserialize;
380 
381     use super::*;
382     use crate::test::TestRequest;
383     use crate::types::{Form, FormConfig};
384 
385     #[derive(Deserialize, Debug, PartialEq)]
386     struct Info {
387         hello: String,
388     }
389 
390     #[actix_rt::test]
test_option()391     async fn test_option() {
392         let (req, mut pl) = TestRequest::default()
393             .insert_header((header::CONTENT_TYPE, "application/x-www-form-urlencoded"))
394             .data(FormConfig::default().limit(4096))
395             .to_http_parts();
396 
397         let r = Option::<Form<Info>>::from_request(&req, &mut pl)
398             .await
399             .unwrap();
400         assert_eq!(r, None);
401 
402         let (req, mut pl) = TestRequest::default()
403             .insert_header((header::CONTENT_TYPE, "application/x-www-form-urlencoded"))
404             .insert_header((header::CONTENT_LENGTH, "9"))
405             .set_payload(Bytes::from_static(b"hello=world"))
406             .to_http_parts();
407 
408         let r = Option::<Form<Info>>::from_request(&req, &mut pl)
409             .await
410             .unwrap();
411         assert_eq!(
412             r,
413             Some(Form(Info {
414                 hello: "world".into()
415             }))
416         );
417 
418         let (req, mut pl) = TestRequest::default()
419             .insert_header((header::CONTENT_TYPE, "application/x-www-form-urlencoded"))
420             .insert_header((header::CONTENT_LENGTH, "9"))
421             .set_payload(Bytes::from_static(b"bye=world"))
422             .to_http_parts();
423 
424         let r = Option::<Form<Info>>::from_request(&req, &mut pl)
425             .await
426             .unwrap();
427         assert_eq!(r, None);
428     }
429 
430     #[actix_rt::test]
test_result()431     async fn test_result() {
432         let (req, mut pl) = TestRequest::default()
433             .insert_header((header::CONTENT_TYPE, "application/x-www-form-urlencoded"))
434             .insert_header((header::CONTENT_LENGTH, "11"))
435             .set_payload(Bytes::from_static(b"hello=world"))
436             .to_http_parts();
437 
438         let r = Result::<Form<Info>, Error>::from_request(&req, &mut pl)
439             .await
440             .unwrap()
441             .unwrap();
442         assert_eq!(
443             r,
444             Form(Info {
445                 hello: "world".into()
446             })
447         );
448 
449         let (req, mut pl) = TestRequest::default()
450             .insert_header((header::CONTENT_TYPE, "application/x-www-form-urlencoded"))
451             .insert_header((header::CONTENT_LENGTH, 9))
452             .set_payload(Bytes::from_static(b"bye=world"))
453             .to_http_parts();
454 
455         let r = Result::<Form<Info>, Error>::from_request(&req, &mut pl)
456             .await
457             .unwrap();
458         assert!(r.is_err());
459     }
460 
461     #[actix_rt::test]
test_uri()462     async fn test_uri() {
463         let req = TestRequest::default().uri("/foo/bar").to_http_request();
464         let uri = Uri::extract(&req).await.unwrap();
465         assert_eq!(uri.path(), "/foo/bar");
466     }
467 
468     #[actix_rt::test]
test_method()469     async fn test_method() {
470         let req = TestRequest::default().method(Method::GET).to_http_request();
471         let method = Method::extract(&req).await.unwrap();
472         assert_eq!(method, Method::GET);
473     }
474 }
475