1 use std::{any::type_name, ops::Deref}; 2 3 use actix_utils::future::{err, ok, Ready}; 4 5 use crate::{dev::Payload, error::ErrorInternalServerError, Error, FromRequest, HttpRequest}; 6 7 /// Request-local data extractor. 8 /// 9 /// Request-local data is arbitrary data attached to an individual request, usually 10 /// by middleware. It can be set via `extensions_mut` on [`HttpRequest`][htr_ext_mut] 11 /// or [`ServiceRequest`][srv_ext_mut]. 12 /// 13 /// Unlike app data, request data is dropped when the request has finished processing. This makes it 14 /// useful as a kind of messaging system between middleware and request handlers. It uses the same 15 /// types-as-keys storage system as app data. 16 /// 17 /// # Mutating Request Data 18 /// Note that since extractors must output owned data, only types that `impl Clone` can use this 19 /// extractor. A clone is taken of the required request data and can, therefore, not be directly 20 /// mutated in-place. To mutate request data, continue to use [`HttpRequest::extensions_mut`] or 21 /// re-insert the cloned data back into the extensions map. A `DerefMut` impl is intentionally not 22 /// provided to make this potential foot-gun more obvious. 23 /// 24 /// # Example 25 /// ```no_run 26 /// # use actix_web::{web, HttpResponse, HttpRequest, Responder}; 27 /// 28 /// #[derive(Debug, Clone, PartialEq)] 29 /// struct FlagFromMiddleware(String); 30 /// 31 /// /// Use the `ReqData<T>` extractor to access request data in a handler. 32 /// async fn handler( 33 /// req: HttpRequest, 34 /// opt_flag: Option<web::ReqData<FlagFromMiddleware>>, 35 /// ) -> impl Responder { 36 /// // use an optional extractor if the middleware is 37 /// // not guaranteed to add this type of requests data 38 /// if let Some(flag) = opt_flag { 39 /// assert_eq!(&flag.into_inner(), req.extensions().get::<FlagFromMiddleware>().unwrap()); 40 /// } 41 /// 42 /// HttpResponse::Ok() 43 /// } 44 /// ``` 45 /// 46 /// [htr_ext_mut]: crate::HttpRequest::extensions_mut 47 /// [srv_ext_mut]: crate::dev::ServiceRequest::extensions_mut 48 #[derive(Debug, Clone)] 49 pub struct ReqData<T: Clone + 'static>(T); 50 51 impl<T: Clone + 'static> ReqData<T> { 52 /// Consumes the `ReqData`, returning its wrapped data. into_inner(self) -> T53 pub fn into_inner(self) -> T { 54 self.0 55 } 56 } 57 58 impl<T: Clone + 'static> Deref for ReqData<T> { 59 type Target = T; 60 deref(&self) -> &T61 fn deref(&self) -> &T { 62 &self.0 63 } 64 } 65 66 impl<T: Clone + 'static> FromRequest for ReqData<T> { 67 type Config = (); 68 type Error = Error; 69 type Future = Ready<Result<Self, Error>>; 70 from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future71 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { 72 if let Some(st) = req.extensions().get::<T>() { 73 ok(ReqData(st.clone())) 74 } else { 75 log::debug!( 76 "Failed to construct App-level ReqData extractor. \ 77 Request path: {:?} (type: {})", 78 req.path(), 79 type_name::<T>(), 80 ); 81 err(ErrorInternalServerError( 82 "Missing expected request extension data", 83 )) 84 } 85 } 86 } 87 88 #[cfg(test)] 89 mod tests { 90 use std::{cell::RefCell, rc::Rc}; 91 92 use futures_util::TryFutureExt as _; 93 94 use super::*; 95 use crate::{ 96 dev::Service, 97 http::{Method, StatusCode}, 98 test::{init_service, TestRequest}, 99 web, App, HttpMessage, HttpResponse, 100 }; 101 102 #[actix_rt::test] req_data_extractor()103 async fn req_data_extractor() { 104 let srv = init_service( 105 App::new() 106 .wrap_fn(|req, srv| { 107 if req.method() == Method::POST { 108 req.extensions_mut().insert(42u32); 109 } 110 111 srv.call(req) 112 }) 113 .service(web::resource("/test").to( 114 |req: HttpRequest, data: Option<ReqData<u32>>| { 115 if req.method() != Method::POST { 116 assert!(data.is_none()); 117 } 118 119 if let Some(data) = data { 120 assert_eq!(*data, 42); 121 assert_eq!( 122 Some(data.into_inner()), 123 req.extensions().get::<u32>().copied() 124 ); 125 } 126 127 HttpResponse::Ok() 128 }, 129 )), 130 ) 131 .await; 132 133 let req = TestRequest::get().uri("/test").to_request(); 134 let resp = srv.call(req).await.unwrap(); 135 assert_eq!(resp.status(), StatusCode::OK); 136 137 let req = TestRequest::post().uri("/test").to_request(); 138 let resp = srv.call(req).await.unwrap(); 139 assert_eq!(resp.status(), StatusCode::OK); 140 } 141 142 #[actix_rt::test] req_data_internal_mutability()143 async fn req_data_internal_mutability() { 144 let srv = init_service( 145 App::new() 146 .wrap_fn(|req, srv| { 147 let data_before = Rc::new(RefCell::new(42u32)); 148 req.extensions_mut().insert(data_before); 149 150 srv.call(req).map_ok(|res| { 151 { 152 let ext = res.request().extensions(); 153 let data_after = ext.get::<Rc<RefCell<u32>>>().unwrap(); 154 assert_eq!(*data_after.borrow(), 53u32); 155 } 156 157 res 158 }) 159 }) 160 .default_service(web::to(|data: ReqData<Rc<RefCell<u32>>>| { 161 assert_eq!(*data.borrow(), 42); 162 *data.borrow_mut() += 11; 163 assert_eq!(*data.borrow(), 53); 164 165 HttpResponse::Ok() 166 })), 167 ) 168 .await; 169 170 let req = TestRequest::get().uri("/test").to_request(); 171 let resp = srv.call(req).await.unwrap(); 172 assert_eq!(resp.status(), StatusCode::OK); 173 } 174 } 175