1use std::{cell::RefCell, mem, rc::Rc};
2
3use actix_http::Request;
4use actix_router::{Path, ResourceDef, Router, Url};
5use actix_service::{boxed, fn_service, Service, ServiceFactory};
6use futures_core::future::LocalBoxFuture;
7use futures_util::future::join_all;
8
9use crate::{
10 body::BoxBody,
11 config::{AppConfig, AppService},
12 data::FnDataFactory,
13 dev::Extensions,
14 guard::Guard,
15 request::{HttpRequest, HttpRequestPool},
16 rmap::ResourceMap,
17 service::{
18 AppServiceFactory, BoxedHttpService, BoxedHttpServiceFactory, ServiceRequest,
19 ServiceResponse,
20 },
21 Error, HttpResponse,
22};
23
24pub struct AppInit<T, B>
28where
29 T: ServiceFactory<
30 ServiceRequest,
31 Config = (),
32 Response = ServiceResponse<B>,
33 Error = Error,
34 InitError = (),
35 >,
36{
37 pub(crate) endpoint: T,
38 pub(crate) extensions: RefCell<Option<Extensions>>,
39 pub(crate) async_data_factories: Rc<[FnDataFactory]>,
40 pub(crate) services: Rc<RefCell<Vec<Box<dyn AppServiceFactory>>>>,
41 pub(crate) default: Option<Rc<BoxedHttpServiceFactory>>,
42 pub(crate) factory_ref: Rc<RefCell<Option<AppRoutingFactory>>>,
43 pub(crate) external: RefCell<Vec<ResourceDef>>,
44}
45
46impl<T, B> ServiceFactory<Request> for AppInit<T, B>
47where
48 T: ServiceFactory<
49 ServiceRequest,
50 Config = (),
51 Response = ServiceResponse<B>,
52 Error = Error,
53 InitError = (),
54 >,
55 T::Future: 'static,
56{
57 type Response = ServiceResponse<B>;
58 type Error = T::Error;
59 type Config = AppConfig;
60 type Service = AppInitService<T::Service, B>;
61 type InitError = T::InitError;
62 type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
63
64 fn new_service(&self, config: AppConfig) -> Self::Future {
65 let default = self.default.clone().unwrap_or_else(|| {
68 Rc::new(boxed::factory(fn_service(|req: ServiceRequest| async {
69 Ok(req.into_response(HttpResponse::NotFound()))
70 })))
71 });
72
73 let mut config = AppService::new(config, Rc::clone(&default));
75
76 mem::take(&mut *self.services.borrow_mut())
78 .into_iter()
79 .for_each(|mut srv| srv.register(&mut config));
80
81 let mut rmap = ResourceMap::new(ResourceDef::prefix(""));
82
83 let (config, services) = config.into_services();
84
85 *self.factory_ref.borrow_mut() = Some(AppRoutingFactory {
87 default,
88 services: services
89 .into_iter()
90 .map(|(mut rdef, srv, guards, nested)| {
91 rmap.add(&mut rdef, nested);
92 (rdef, srv, RefCell::new(guards))
93 })
94 .collect::<Vec<_>>()
95 .into_boxed_slice()
96 .into(),
97 });
98
99 for mut rdef in mem::take(&mut *self.external.borrow_mut()) {
101 rmap.add(&mut rdef, None);
102 }
103
104 let rmap = Rc::new(rmap);
106 ResourceMap::finish(&rmap);
107
108 let factory_futs = join_all(self.async_data_factories.iter().map(|f| f()));
110
111 let endpoint_fut = self.endpoint.new_service(());
113
114 let mut app_data = self.extensions.borrow_mut().take().unwrap_or_default();
116
117 Box::pin(async move {
118 let async_data_factories = factory_futs
120 .await
121 .into_iter()
122 .collect::<Result<Vec<_>, _>>()
123 .map_err(|_| ())?;
124
125 let service = endpoint_fut.await?;
127
128 for factory in &async_data_factories {
130 factory.create(&mut app_data);
131 }
132
133 Ok(AppInitService {
134 service,
135 app_data: Rc::new(app_data),
136 app_state: AppInitServiceState::new(rmap, config),
137 })
138 })
139 }
140}
141
142pub struct AppInitService<T, B>
146where
147 T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
148{
149 service: T,
150 app_data: Rc<Extensions>,
151 app_state: Rc<AppInitServiceState>,
152}
153
154pub(crate) struct AppInitServiceState {
156 rmap: Rc<ResourceMap>,
157 config: AppConfig,
158 pool: HttpRequestPool,
159}
160
161impl AppInitServiceState {
162 pub(crate) fn new(rmap: Rc<ResourceMap>, config: AppConfig) -> Rc<Self> {
164 Rc::new(AppInitServiceState {
165 rmap,
166 config,
167 pool: HttpRequestPool::default(),
168 })
169 }
170
171 #[inline]
173 pub(crate) fn rmap(&self) -> &ResourceMap {
174 &self.rmap
175 }
176
177 #[inline]
179 pub(crate) fn config(&self) -> &AppConfig {
180 &self.config
181 }
182
183 #[inline]
185 pub(crate) fn pool(&self) -> &HttpRequestPool {
186 &self.pool
187 }
188}
189
190impl<T, B> Service<Request> for AppInitService<T, B>
191where
192 T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
193{
194 type Response = ServiceResponse<B>;
195 type Error = T::Error;
196 type Future = T::Future;
197
198 actix_service::forward_ready!(service);
199
200 fn call(&self, mut req: Request) -> Self::Future {
201 let extensions = Rc::new(RefCell::new(req.take_req_data()));
202 let conn_data = req.take_conn_data();
203 let (head, payload) = req.into_parts();
204
205 let req = match self.app_state.pool().pop() {
206 Some(mut req) => {
207 let inner = Rc::get_mut(&mut req.inner).unwrap();
208 inner.path.get_mut().update(&head.uri);
209 inner.path.reset();
210 inner.head = head;
211 inner.conn_data = conn_data;
212 inner.extensions = extensions;
213 req
214 }
215
216 None => HttpRequest::new(
217 Path::new(Url::new(head.uri.clone())),
218 head,
219 Rc::clone(&self.app_state),
220 Rc::clone(&self.app_data),
221 conn_data,
222 extensions,
223 ),
224 };
225
226 self.service.call(ServiceRequest::new(req, payload))
227 }
228}
229
230impl<T, B> Drop for AppInitService<T, B>
231where
232 T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
233{
234 fn drop(&mut self) {
235 self.app_state.pool().clear();
236 }
237}
238
239pub struct AppRoutingFactory {
240 #[allow(clippy::type_complexity)]
241 services: Rc<
242 [(
243 ResourceDef,
244 BoxedHttpServiceFactory,
245 RefCell<Option<Vec<Box<dyn Guard>>>>,
246 )],
247 >,
248 default: Rc<BoxedHttpServiceFactory>,
249}
250
251impl ServiceFactory<ServiceRequest> for AppRoutingFactory {
252 type Response = ServiceResponse;
253 type Error = Error;
254 type Config = ();
255 type Service = AppRouting;
256 type InitError = ();
257 type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
258
259 fn new_service(&self, _: ()) -> Self::Future {
260 let factory_fut = join_all(self.services.iter().map(|(path, factory, guards)| {
262 let path = path.clone();
263 let guards = guards.borrow_mut().take().unwrap_or_default();
264 let factory_fut = factory.new_service(());
265 async move {
266 factory_fut
267 .await
268 .map(move |service| (path, guards, service))
269 }
270 }));
271
272 let default_fut = self.default.new_service(());
274
275 Box::pin(async move {
276 let default = default_fut.await?;
277
278 let router = factory_fut
280 .await
281 .into_iter()
282 .collect::<Result<Vec<_>, _>>()?
283 .drain(..)
284 .fold(Router::build(), |mut router, (path, guards, service)| {
285 router.push(path, service, guards);
286 router
287 })
288 .finish();
289
290 Ok(AppRouting { router, default })
291 })
292 }
293}
294
295pub struct AppRouting {
297 router: Router<BoxedHttpService, Vec<Box<dyn Guard>>>,
298 default: BoxedHttpService,
299}
300
301impl Service<ServiceRequest> for AppRouting {
302 type Response = ServiceResponse<BoxBody>;
303 type Error = Error;
304 type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
305
306 actix_service::always_ready!();
307
308 fn call(&self, mut req: ServiceRequest) -> Self::Future {
309 let res = self.router.recognize_fn(&mut req, |req, guards| {
310 let guard_ctx = req.guard_ctx();
311 guards.iter().all(|guard| guard.check(&guard_ctx))
312 });
313
314 if let Some((srv, _info)) = res {
315 srv.call(req)
316 } else {
317 self.default.call(req)
318 }
319 }
320}
321
322pub struct AppEntry {
324 factory: Rc<RefCell<Option<AppRoutingFactory>>>,
325}
326
327impl AppEntry {
328 pub fn new(factory: Rc<RefCell<Option<AppRoutingFactory>>>) -> Self {
329 AppEntry { factory }
330 }
331}
332
333impl ServiceFactory<ServiceRequest> for AppEntry {
334 type Response = ServiceResponse;
335 type Error = Error;
336 type Config = ();
337 type Service = AppRouting;
338 type InitError = ();
339 type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
340
341 fn new_service(&self, _: ()) -> Self::Future {
342 self.factory.borrow_mut().as_mut().unwrap().new_service(())
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use std::sync::{
349 atomic::{AtomicBool, Ordering},
350 Arc,
351 };
352
353 use actix_service::Service;
354
355 use crate::{
356 test::{init_service, TestRequest},
357 web, App, HttpResponse,
358 };
359
360 struct DropData(Arc<AtomicBool>);
361
362 impl Drop for DropData {
363 fn drop(&mut self) {
364 self.0.store(true, Ordering::Relaxed);
365 }
366 }
367
368 #[allow(deprecated)]
370 #[actix_rt::test]
371 async fn test_drop_data() {
372 let data = Arc::new(AtomicBool::new(false));
373
374 {
375 let app = init_service(
376 App::new()
377 .data(DropData(data.clone()))
378 .service(web::resource("/test").to(HttpResponse::Ok)),
379 )
380 .await;
381 let req = TestRequest::with_uri("/test").to_request();
382 let _ = app.call(req).await.unwrap();
383 }
384 assert!(data.load(Ordering::Relaxed));
385 }
386}