1
- use std:: net:: SocketAddr ;
2
- use std :: rc :: Rc ;
3
-
4
- use actix_http :: Extensions ;
5
- use actix_router :: ResourceDef ;
6
- use actix_service :: { boxed , IntoServiceFactory , ServiceFactory } ;
7
-
8
- use crate :: data :: Data ;
9
- use crate :: error :: Error ;
10
- use crate :: guard :: Guard ;
11
- use crate :: resource :: Resource ;
12
- use crate :: rmap :: ResourceMap ;
13
- use crate :: route :: Route ;
14
- use crate :: service :: {
15
- AppServiceFactory , HttpServiceFactory , ServiceFactoryWrapper , ServiceRequest ,
16
- ServiceResponse ,
1
+ use std:: { net:: SocketAddr , rc :: Rc } ;
2
+
3
+ use actix_service :: { boxed , IntoServiceFactory , ServiceFactory , ServiceFactoryExt as _ } ;
4
+
5
+ use crate :: {
6
+ data :: Data ,
7
+ dev :: { Extensions , ResourceDef } ,
8
+ error :: Error ,
9
+ guard :: Guard ,
10
+ resource :: Resource ,
11
+ rmap :: ResourceMap ,
12
+ route :: Route ,
13
+ service :: {
14
+ AppServiceFactory , BoxedHttpServiceFactory , HttpServiceFactory , ServiceFactoryWrapper ,
15
+ ServiceRequest , ServiceResponse ,
16
+ } ,
17
17
} ;
18
18
19
19
type Guards = Vec < Box < dyn Guard > > ;
20
- type HttpNewService = boxed:: BoxServiceFactory < ( ) , ServiceRequest , ServiceResponse , Error , ( ) > ;
21
20
22
21
/// Application configuration
23
22
pub struct AppService {
24
23
config : AppConfig ,
25
24
root : bool ,
26
- default : Rc < HttpNewService > ,
25
+ default : Rc < BoxedHttpServiceFactory > ,
27
26
#[ allow( clippy:: type_complexity) ]
28
27
services : Vec < (
29
28
ResourceDef ,
30
- HttpNewService ,
29
+ BoxedHttpServiceFactory ,
31
30
Option < Guards > ,
32
31
Option < Rc < ResourceMap > > ,
33
32
) > ,
34
33
}
35
34
36
35
impl AppService {
37
36
/// Crate server settings instance.
38
- pub ( crate ) fn new ( config : AppConfig , default : Rc < HttpNewService > ) -> Self {
37
+ pub ( crate ) fn new ( config : AppConfig , default : Rc < BoxedHttpServiceFactory > ) -> Self {
39
38
AppService {
40
39
config,
41
40
default,
@@ -56,7 +55,7 @@ impl AppService {
56
55
AppConfig ,
57
56
Vec < (
58
57
ResourceDef ,
59
- HttpNewService ,
58
+ BoxedHttpServiceFactory ,
60
59
Option < Guards > ,
61
60
Option < Rc < ResourceMap > > ,
62
61
) > ,
@@ -81,7 +80,7 @@ impl AppService {
81
80
}
82
81
83
82
/// Returns default handler factory.
84
- pub fn default_service ( & self ) -> Rc < HttpNewService > {
83
+ pub fn default_service ( & self ) -> Rc < BoxedHttpServiceFactory > {
85
84
self . default . clone ( )
86
85
}
87
86
@@ -187,6 +186,7 @@ pub struct ServiceConfig {
187
186
pub ( crate ) services : Vec < Box < dyn AppServiceFactory > > ,
188
187
pub ( crate ) external : Vec < ResourceDef > ,
189
188
pub ( crate ) app_data : Extensions ,
189
+ pub ( crate ) default : Option < Rc < BoxedHttpServiceFactory > > ,
190
190
}
191
191
192
192
impl ServiceConfig {
@@ -195,6 +195,7 @@ impl ServiceConfig {
195
195
services : Vec :: new ( ) ,
196
196
external : Vec :: new ( ) ,
197
197
app_data : Extensions :: new ( ) ,
198
+ default : None ,
198
199
}
199
200
}
200
201
@@ -215,6 +216,29 @@ impl ServiceConfig {
215
216
self
216
217
}
217
218
219
+ /// Default service to be used if no matching resource could be found.
220
+ ///
221
+ /// Counterpart to [`App::default_service()`](crate::App::default_service).
222
+ pub fn default_service < F , U > ( & mut self , f : F ) -> & mut Self
223
+ where
224
+ F : IntoServiceFactory < U , ServiceRequest > ,
225
+ U : ServiceFactory <
226
+ ServiceRequest ,
227
+ Config = ( ) ,
228
+ Response = ServiceResponse ,
229
+ Error = Error ,
230
+ > + ' static ,
231
+ U :: InitError : std:: fmt:: Debug ,
232
+ {
233
+ let svc = f
234
+ . into_factory ( )
235
+ . map_init_err ( |err| log:: error!( "Can not construct default service: {:?}" , err) ) ;
236
+
237
+ self . default = Some ( Rc :: new ( boxed:: factory ( svc) ) ) ;
238
+
239
+ self
240
+ }
241
+
218
242
/// Run external configuration as part of the application building process
219
243
///
220
244
/// Counterpart to [`App::configure()`](crate::App::configure) that allows for easy nesting.
@@ -322,6 +346,38 @@ mod tests {
322
346
assert_eq ! ( body, Bytes :: from_static( b"https://youtube.com/watch/12345" ) ) ;
323
347
}
324
348
349
+ #[ actix_rt:: test]
350
+ async fn registers_default_service ( ) {
351
+ let srv = init_service (
352
+ App :: new ( )
353
+ . configure ( |cfg| {
354
+ cfg. default_service (
355
+ web:: get ( ) . to ( || HttpResponse :: NotFound ( ) . body ( "four oh four" ) ) ,
356
+ ) ;
357
+ } )
358
+ . service ( web:: scope ( "/scoped" ) . configure ( |cfg| {
359
+ cfg. default_service (
360
+ web:: get ( ) . to ( || HttpResponse :: NotFound ( ) . body ( "scoped four oh four" ) ) ,
361
+ ) ;
362
+ } ) ) ,
363
+ )
364
+ . await ;
365
+
366
+ // app registers default service
367
+ let req = TestRequest :: with_uri ( "/path/i/did/not-configure" ) . to_request ( ) ;
368
+ let resp = call_service ( & srv, req) . await ;
369
+ assert_eq ! ( resp. status( ) , StatusCode :: NOT_FOUND ) ;
370
+ let body = read_body ( resp) . await ;
371
+ assert_eq ! ( body, Bytes :: from_static( b"four oh four" ) ) ;
372
+
373
+ // scope registers default service
374
+ let req = TestRequest :: with_uri ( "/scoped/path/i/did/not-configure" ) . to_request ( ) ;
375
+ let resp = call_service ( & srv, req) . await ;
376
+ assert_eq ! ( resp. status( ) , StatusCode :: NOT_FOUND ) ;
377
+ let body = read_body ( resp) . await ;
378
+ assert_eq ! ( body, Bytes :: from_static( b"scoped four oh four" ) ) ;
379
+ }
380
+
325
381
#[ actix_rt:: test]
326
382
async fn test_service ( ) {
327
383
let srv = init_service ( App :: new ( ) . configure ( |cfg| {
0 commit comments