mirror of
https://github.com/actix/actix-web.git
synced 2024-12-23 00:26:34 +00:00
Merge pull request #339 from joshleeb/propogate-scope-default-resource
Propagate scope default resource
This commit is contained in:
commit
5a9992736f
4 changed files with 60 additions and 8 deletions
|
@ -25,6 +25,8 @@
|
|||
|
||||
* `HttpRequest::url_for_static()` for a named route with no variables segments
|
||||
|
||||
* Propagation of the application's default resource to scopes that haven't set a default resource.
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct HttpApplication<S = ()> {
|
|||
#[doc(hidden)]
|
||||
pub struct Inner<S> {
|
||||
prefix: usize,
|
||||
default: ResourceHandler<S>,
|
||||
default: Rc<RefCell<ResourceHandler<S>>>,
|
||||
encoding: ContentEncoding,
|
||||
resources: Vec<ResourceHandler<S>>,
|
||||
handlers: Vec<PrefixHandlerType<S>>,
|
||||
|
@ -51,7 +51,7 @@ impl<S: 'static> PipelineHandler<S> for Inner<S> {
|
|||
match htype {
|
||||
HandlerType::Normal(idx) => match self.resources[idx].handle(req) {
|
||||
Ok(result) => result,
|
||||
Err(req) => match self.default.handle(req) {
|
||||
Err(req) => match self.default.borrow_mut().handle(req) {
|
||||
Ok(result) => result,
|
||||
Err(_) => AsyncResult::ok(HttpResponse::new(StatusCode::NOT_FOUND)),
|
||||
},
|
||||
|
@ -60,7 +60,7 @@ impl<S: 'static> PipelineHandler<S> for Inner<S> {
|
|||
PrefixHandlerType::Handler(_, ref mut hnd) => hnd.handle(req),
|
||||
PrefixHandlerType::Scope(_, ref mut hnd, _) => hnd.handle(req),
|
||||
},
|
||||
HandlerType::Default => match self.default.handle(req) {
|
||||
HandlerType::Default => match self.default.borrow_mut().handle(req) {
|
||||
Ok(result) => result,
|
||||
Err(_) => AsyncResult::ok(HttpResponse::new(StatusCode::NOT_FOUND)),
|
||||
},
|
||||
|
@ -172,7 +172,7 @@ struct ApplicationParts<S> {
|
|||
state: S,
|
||||
prefix: String,
|
||||
settings: ServerSettings,
|
||||
default: ResourceHandler<S>,
|
||||
default: Rc<RefCell<ResourceHandler<S>>>,
|
||||
resources: Vec<(Resource, Option<ResourceHandler<S>>)>,
|
||||
handlers: Vec<PrefixHandlerType<S>>,
|
||||
external: HashMap<String, Resource>,
|
||||
|
@ -223,7 +223,7 @@ where
|
|||
state,
|
||||
prefix: "/".to_owned(),
|
||||
settings: ServerSettings::default(),
|
||||
default: ResourceHandler::default_not_found(),
|
||||
default: Rc::new(RefCell::new(ResourceHandler::default_not_found())),
|
||||
resources: Vec::new(),
|
||||
handlers: Vec::new(),
|
||||
external: HashMap::new(),
|
||||
|
@ -474,7 +474,7 @@ where
|
|||
{
|
||||
{
|
||||
let parts = self.parts.as_mut().expect("Use after finish");
|
||||
f(&mut parts.default);
|
||||
f(&mut parts.default.borrow_mut());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -615,7 +615,7 @@ where
|
|||
|
||||
/// Finish application configuration and create `HttpHandler` object.
|
||||
pub fn finish(&mut self) -> HttpApplication<S> {
|
||||
let parts = self.parts.take().expect("Use after finish");
|
||||
let mut parts = self.parts.take().expect("Use after finish");
|
||||
let prefix = parts.prefix.trim().trim_right_matches('/');
|
||||
let (prefix, prefix_len) = if prefix.is_empty() {
|
||||
("/".to_owned(), 0)
|
||||
|
@ -628,11 +628,19 @@ where
|
|||
resources.push((pattern, None));
|
||||
}
|
||||
|
||||
for ref mut handler in parts.handlers.iter_mut() {
|
||||
if let PrefixHandlerType::Scope(_, ref mut route_handler, _) = handler {
|
||||
if !route_handler.has_default_resource() {
|
||||
route_handler.default_resource(Rc::clone(&parts.default));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let (router, resources) = Router::new(&prefix, parts.settings, resources);
|
||||
|
||||
let inner = Rc::new(RefCell::new(Inner {
|
||||
prefix: prefix_len,
|
||||
default: parts.default,
|
||||
default: Rc::clone(&parts.default),
|
||||
encoding: parts.encoding,
|
||||
handlers: parts.handlers,
|
||||
resources,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::future::{err, ok, Future};
|
||||
use futures::{Async, Poll};
|
||||
|
@ -8,6 +10,7 @@ use error::Error;
|
|||
use http::StatusCode;
|
||||
use httprequest::HttpRequest;
|
||||
use httpresponse::HttpResponse;
|
||||
use resource::ResourceHandler;
|
||||
|
||||
/// Trait defines object that could be registered as route handler
|
||||
#[allow(unused_variables)]
|
||||
|
@ -403,6 +406,14 @@ where
|
|||
// /// Trait defines object that could be registered as resource route
|
||||
pub(crate) trait RouteHandler<S>: 'static {
|
||||
fn handle(&mut self, req: HttpRequest<S>) -> AsyncResult<HttpResponse>;
|
||||
|
||||
fn has_default_resource(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn default_resource(&mut self, default: Rc<RefCell<ResourceHandler<S>>>) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Route handler wrapper for Handler
|
||||
|
|
31
src/scope.rs
31
src/scope.rs
|
@ -405,6 +405,14 @@ impl<S: 'static> RouteHandler<S> for Scope<S> {
|
|||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn has_default_resource(&self) -> bool {
|
||||
self.default.is_some()
|
||||
}
|
||||
|
||||
fn default_resource(&mut self, default: ScopeResource<S>) {
|
||||
self.default = Some(default);
|
||||
}
|
||||
}
|
||||
|
||||
struct Wrapper<S: 'static> {
|
||||
|
@ -1188,4 +1196,27 @@ mod tests {
|
|||
let resp = app.run(req);
|
||||
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_resource_propagation() {
|
||||
let mut app = App::new()
|
||||
.scope("/app1", |scope| {
|
||||
scope.default_resource(|r| r.f(|_| HttpResponse::BadRequest()))
|
||||
})
|
||||
.scope("/app2", |scope| scope)
|
||||
.default_resource(|r| r.f(|_| HttpResponse::MethodNotAllowed()))
|
||||
.finish();
|
||||
|
||||
let req = TestRequest::with_uri("/non-exist").finish();
|
||||
let resp = app.run(req);
|
||||
assert_eq!(resp.as_msg().status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||
|
||||
let req = TestRequest::with_uri("/app1/non-exist").finish();
|
||||
let resp = app.run(req);
|
||||
assert_eq!(resp.as_msg().status(), StatusCode::BAD_REQUEST);
|
||||
|
||||
let req = TestRequest::with_uri("/app2/non-exist").finish();
|
||||
let resp = app.run(req);
|
||||
assert_eq!(resp.as_msg().status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue