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