diff --git a/CHANGES.md b/CHANGES.md index 31ebee53..b0193c0e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ * Allow to gracefully stop test server via `TestServer::stop()` +* Allow to specify multi-patterns for resources ## [2.0.0-rc] - 2019-12-20 diff --git a/Cargo.toml b/Cargo.toml index 04a559f1..1adae97b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ rustls = ["actix-tls/rustls", "awc/rustls", "rust-tls"] actix-codec = "0.2.0" actix-service = "1.0.1" actix-utils = "1.0.4" -actix-router = "0.2.0" +actix-router = "0.2.1" actix-rt = "1.0.0" actix-server = "1.0.0" actix-testing = "1.0.0" @@ -115,4 +115,4 @@ actix-identity = { path = "actix-identity" } actix-session = { path = "actix-session" } actix-files = { path = "actix-files" } actix-multipart = { path = "actix-multipart" } -awc = { path = "awc" } +awc = { path = "awc" } \ No newline at end of file diff --git a/actix-cors/src/lib.rs b/actix-cors/src/lib.rs index ddb20d2b..429fe9ea 100644 --- a/actix-cors/src/lib.rs +++ b/actix-cors/src/lib.rs @@ -814,7 +814,7 @@ where res } } - .boxed_local(), + .boxed_local(), ) } } diff --git a/actix-framed/src/helpers.rs b/actix-framed/src/helpers.rs index d08ca25a..29492e45 100644 --- a/actix-framed/src/helpers.rs +++ b/actix-framed/src/helpers.rs @@ -66,7 +66,7 @@ where service }) } - .boxed_local() + .boxed_local() } } diff --git a/actix-framed/src/route.rs b/actix-framed/src/route.rs index 03e48e4d..793f4627 100644 --- a/actix-framed/src/route.rs +++ b/actix-framed/src/route.rs @@ -154,6 +154,6 @@ where } Ok(()) } - .boxed_local() + .boxed_local() } } diff --git a/actix-identity/src/lib.rs b/actix-identity/src/lib.rs index 5dfd2ae6..b10a419d 100644 --- a/actix-identity/src/lib.rs +++ b/actix-identity/src/lib.rs @@ -294,7 +294,7 @@ where Err(err) => Ok(req.error_response(err)), } } - .boxed_local() + .boxed_local() } } diff --git a/actix-session/src/cookie.rs b/actix-session/src/cookie.rs index 5d66d653..75eef0c0 100644 --- a/actix-session/src/cookie.rs +++ b/actix-session/src/cookie.rs @@ -354,7 +354,7 @@ where } }) } - .boxed_local() + .boxed_local() } } diff --git a/src/lib.rs b/src/lib.rs index b8d358d8..a9965229 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,12 +151,13 @@ pub mod dev { pub use actix_server::Server; pub use actix_service::{Service, Transform}; - pub(crate) fn insert_slash(path: &str) -> String { - let mut path = path.to_owned(); - if !path.is_empty() && !path.starts_with('/') { - path.insert(0, '/'); - }; - path + pub(crate) fn insert_slash(mut patterns: Vec) -> Vec { + for path in &mut patterns { + if !path.is_empty() && !path.starts_with('/') { + path.insert(0, '/'); + }; + } + patterns } use crate::http::header::ContentEncoding; diff --git a/src/middleware/defaultheaders.rs b/src/middleware/defaultheaders.rs index 464be1ac..ba001c77 100644 --- a/src/middleware/defaultheaders.rs +++ b/src/middleware/defaultheaders.rs @@ -150,7 +150,7 @@ where } Ok(res) } - .boxed_local() + .boxed_local() } } diff --git a/src/middleware/errhandlers.rs b/src/middleware/errhandlers.rs index ed1e4c99..71886af0 100644 --- a/src/middleware/errhandlers.rs +++ b/src/middleware/errhandlers.rs @@ -140,7 +140,7 @@ where Ok(res) } } - .boxed_local() + .boxed_local() } } diff --git a/src/resource.rs b/src/resource.rs index 2ee08441..d60d5096 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -6,6 +6,7 @@ use std::rc::Rc; use std::task::{Context, Poll}; use actix_http::{Error, Extensions, Response}; +use actix_router::IntoPattern; use actix_service::boxed::{self, BoxService, BoxServiceFactory}; use actix_service::{ apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory, Transform, @@ -48,7 +49,7 @@ type HttpNewService = BoxServiceFactory<(), ServiceRequest, ServiceResponse, Err /// Default behavior could be overriden with `default_resource()` method. pub struct Resource { endpoint: T, - rdef: String, + rdef: Vec, name: Option, routes: Vec, data: Option, @@ -58,12 +59,12 @@ pub struct Resource { } impl Resource { - pub fn new(path: &str) -> Resource { + pub fn new(path: T) -> Resource { let fref = Rc::new(RefCell::new(None)); Resource { routes: Vec::new(), - rdef: path.to_string(), + rdef: path.patterns(), name: None, endpoint: ResourceEndpoint::new(fref.clone()), factory_ref: fref, @@ -381,9 +382,9 @@ where Some(std::mem::replace(&mut self.guards, Vec::new())) }; let mut rdef = if config.is_root() || !self.rdef.is_empty() { - ResourceDef::new(&insert_slash(&self.rdef)) + ResourceDef::new(insert_slash(self.rdef.clone())) } else { - ResourceDef::new(&self.rdef) + ResourceDef::new(self.rdef.clone()) }; if let Some(ref name) = self.name { *rdef.name_mut() = name.clone(); @@ -660,6 +661,23 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); } + #[actix_rt::test] + async fn test_pattern() { + let mut srv = + init_service(App::new().service(web::resource(["/test", "/test2"]).to(|| { + async { + Ok::<_, Error>(HttpResponse::Ok()) + } + }))) + .await; + let req = TestRequest::with_uri("/test").to_request(); + let resp = call_service(&mut srv, req).await; + assert_eq!(resp.status(), StatusCode::OK); + let req = TestRequest::with_uri("/test2").to_request(); + let resp = call_service(&mut srv, req).await; + assert_eq!(resp.status(), StatusCode::OK); + } + #[actix_rt::test] async fn test_default_resource() { let mut srv = init_service( diff --git a/src/service.rs b/src/service.rs index b58fb5b4..e51be996 100644 --- a/src/service.rs +++ b/src/service.rs @@ -8,7 +8,7 @@ use actix_http::{ Error, Extensions, HttpMessage, Payload, PayloadStream, RequestHead, Response, ResponseHead, }; -use actix_router::{Path, Resource, ResourceDef, Url}; +use actix_router::{IntoPattern, Path, Resource, ResourceDef, Url}; use actix_service::{IntoServiceFactory, ServiceFactory}; use crate::config::{AppConfig, AppService}; @@ -422,16 +422,16 @@ impl fmt::Debug for ServiceResponse { } pub struct WebService { - rdef: String, + rdef: Vec, name: Option, guards: Vec>, } impl WebService { /// Create new `WebService` instance. - pub fn new(path: &str) -> Self { + pub fn new(path: T) -> Self { WebService { - rdef: path.to_string(), + rdef: path.patterns(), name: None, guards: Vec::new(), } @@ -491,7 +491,7 @@ impl WebService { struct WebServiceImpl { srv: T, - rdef: String, + rdef: Vec, name: Option, guards: Vec>, } @@ -514,9 +514,9 @@ where }; let mut rdef = if config.is_root() || !self.rdef.is_empty() { - ResourceDef::new(&insert_slash(&self.rdef)) + ResourceDef::new(insert_slash(self.rdef)) } else { - ResourceDef::new(&self.rdef) + ResourceDef::new(self.rdef) }; if let Some(ref name) = self.name { *rdef.name_mut() = name.clone(); diff --git a/src/types/form.rs b/src/types/form.rs index 333ecbd6..d917345e 100644 --- a/src/types/form.rs +++ b/src/types/form.rs @@ -365,7 +365,7 @@ where .map_err(|_| UrlencodedError::Parse) } } - .boxed_local(), + .boxed_local(), ); self.poll(cx) } diff --git a/src/types/json.rs b/src/types/json.rs index adb425cd..fb00bf7a 100644 --- a/src/types/json.rs +++ b/src/types/json.rs @@ -396,7 +396,7 @@ where } Ok(serde_json::from_slice::(&body)?) } - .boxed_local(), + .boxed_local(), ); self.poll(cx) diff --git a/src/types/payload.rs b/src/types/payload.rs index dd7a84f3..449e6c5b 100644 --- a/src/types/payload.rs +++ b/src/types/payload.rs @@ -229,7 +229,7 @@ impl FromRequest for String { .ok_or_else(|| ErrorBadRequest("Can not decode body"))?) } } - .boxed_local(), + .boxed_local(), ) } } @@ -391,7 +391,7 @@ impl Future for HttpMessageBody { } Ok(body.freeze()) } - .boxed_local(), + .boxed_local(), ); self.poll(cx) } diff --git a/src/web.rs b/src/web.rs index 51094c32..50d99479 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,5 +1,6 @@ //! Essentials helper functions and types for application registration. use actix_http::http::Method; +use actix_router::IntoPattern; use futures::Future; pub use actix_http::Response as HttpResponse; @@ -50,7 +51,7 @@ pub use crate::types::*; /// .route(web::head().to(|| HttpResponse::MethodNotAllowed())) /// ); /// ``` -pub fn resource(path: &str) -> Resource { +pub fn resource(path: T) -> Resource { Resource::new(path) } @@ -249,7 +250,7 @@ where /// .finish(my_service) /// ); /// ``` -pub fn service(path: &str) -> WebService { +pub fn service(path: T) -> WebService { WebService::new(path) }