mirror of
https://github.com/actix/actix-web.git
synced 2024-12-24 00:50:36 +00:00
allow to handle entire sub path
This commit is contained in:
parent
284b59722a
commit
9040f588af
1 changed files with 86 additions and 12 deletions
|
@ -5,6 +5,7 @@ use std::collections::HashMap;
|
||||||
use handler::Reply;
|
use handler::Reply;
|
||||||
use router::{Router, Pattern};
|
use router::{Router, Pattern};
|
||||||
use resource::Resource;
|
use resource::Resource;
|
||||||
|
use handler::{Handler, RouteHandler, WrapHandler};
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use channel::{HttpHandler, IntoHttpHandler, HttpHandlerTask};
|
use channel::{HttpHandler, IntoHttpHandler, HttpHandlerTask};
|
||||||
use pipeline::{Pipeline, PipelineHandler};
|
use pipeline::{Pipeline, PipelineHandler};
|
||||||
|
@ -24,6 +25,7 @@ pub(crate) struct Inner<S> {
|
||||||
default: Resource<S>,
|
default: Resource<S>,
|
||||||
router: Router,
|
router: Router,
|
||||||
resources: Vec<Resource<S>>,
|
resources: Vec<Resource<S>>,
|
||||||
|
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> PipelineHandler<S> for Inner<S> {
|
impl<S: 'static> PipelineHandler<S> for Inner<S> {
|
||||||
|
@ -32,6 +34,17 @@ impl<S: 'static> PipelineHandler<S> for Inner<S> {
|
||||||
if let Some(idx) = self.router.recognize(&mut req) {
|
if let Some(idx) = self.router.recognize(&mut req) {
|
||||||
self.resources[idx].handle(req.clone(), Some(&mut self.default))
|
self.resources[idx].handle(req.clone(), Some(&mut self.default))
|
||||||
} else {
|
} else {
|
||||||
|
for &mut (ref prefix, ref mut handler) in &mut self.handlers {
|
||||||
|
let m = {
|
||||||
|
let path = req.path();
|
||||||
|
path.starts_with(prefix) && (
|
||||||
|
path.len() == prefix.len() ||
|
||||||
|
path.split_at(prefix.len()).1.starts_with('/'))
|
||||||
|
};
|
||||||
|
if m {
|
||||||
|
return handler.handle(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
self.default.handle(req, None)
|
self.default.handle(req, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +86,7 @@ struct ApplicationParts<S> {
|
||||||
settings: ServerSettings,
|
settings: ServerSettings,
|
||||||
default: Resource<S>,
|
default: Resource<S>,
|
||||||
resources: HashMap<Pattern, Option<Resource<S>>>,
|
resources: HashMap<Pattern, Option<Resource<S>>>,
|
||||||
|
handlers: Vec<(String, Box<RouteHandler<S>>)>,
|
||||||
external: HashMap<String, Pattern>,
|
external: HashMap<String, Pattern>,
|
||||||
middlewares: Vec<Box<Middleware<S>>>,
|
middlewares: Vec<Box<Middleware<S>>>,
|
||||||
}
|
}
|
||||||
|
@ -94,6 +108,7 @@ impl Application<()> {
|
||||||
settings: ServerSettings::default(),
|
settings: ServerSettings::default(),
|
||||||
default: Resource::default_not_found(),
|
default: Resource::default_not_found(),
|
||||||
resources: HashMap::new(),
|
resources: HashMap::new(),
|
||||||
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
middlewares: Vec::new(),
|
middlewares: Vec::new(),
|
||||||
})
|
})
|
||||||
|
@ -122,6 +137,7 @@ impl<S> Application<S> where S: 'static {
|
||||||
settings: ServerSettings::default(),
|
settings: ServerSettings::default(),
|
||||||
default: Resource::default_not_found(),
|
default: Resource::default_not_found(),
|
||||||
resources: HashMap::new(),
|
resources: HashMap::new(),
|
||||||
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
middlewares: Vec::new(),
|
middlewares: Vec::new(),
|
||||||
})
|
})
|
||||||
|
@ -133,7 +149,7 @@ impl<S> Application<S> where S: 'static {
|
||||||
/// Only requests that matches application's prefix get processed by this application.
|
/// Only requests that matches application's prefix get processed by this application.
|
||||||
/// Application prefix always contains laading "/" slash. If supplied prefix
|
/// Application prefix always contains laading "/" slash. If supplied prefix
|
||||||
/// does not contain leading slash, it get inserted. Prefix should
|
/// does not contain leading slash, it get inserted. Prefix should
|
||||||
/// consists of valud path segments. i.e for application with
|
/// consists valid path segments. i.e for application with
|
||||||
/// prefix `/app` any request with following paths `/app`, `/app/` or `/app/test`
|
/// prefix `/app` any request with following paths `/app`, `/app/` or `/app/test`
|
||||||
/// would match, but path `/application` would not match.
|
/// would match, but path `/application` would not match.
|
||||||
///
|
///
|
||||||
|
@ -194,8 +210,7 @@ impl<S> Application<S> where S: 'static {
|
||||||
/// .resource("/test", |r| {
|
/// .resource("/test", |r| {
|
||||||
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
|
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
|
||||||
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
|
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
|
||||||
/// })
|
/// });
|
||||||
/// .finish();
|
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn resource<F>(mut self, path: &str, f: F) -> Application<S>
|
pub fn resource<F>(mut self, path: &str, f: F) -> Application<S>
|
||||||
|
@ -267,6 +282,36 @@ impl<S> Application<S> where S: 'static {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure handler for specific path prefix.
|
||||||
|
///
|
||||||
|
/// Path prefix consists valid path segments. i.e for prefix `/app`
|
||||||
|
/// any request with following paths `/app`, `/app/` or `/app/test`
|
||||||
|
/// would match, but path `/application` would not match.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// use actix_web::*;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = Application::new()
|
||||||
|
/// .handler("/app", |req: HttpRequest| {
|
||||||
|
/// match *req.method() {
|
||||||
|
/// Method::GET => httpcodes::HTTPOk,
|
||||||
|
/// Method::POST => httpcodes::HTTPMethodNotAllowed,
|
||||||
|
/// _ => httpcodes::HTTPNotFound,
|
||||||
|
/// }});
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn handler<H: Handler<S>>(mut self, path: &str, handler: H) -> Application<S>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
let path = path.trim().trim_right_matches('/').to_owned();
|
||||||
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
|
parts.handlers.push((path, Box::new(WrapHandler::new(handler))));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Register a middleware
|
/// Register a middleware
|
||||||
pub fn middleware<T>(mut self, mw: T) -> Application<S>
|
pub fn middleware<T>(mut self, mw: T) -> Application<S>
|
||||||
where T: Middleware<S> + 'static
|
where T: Middleware<S> + 'static
|
||||||
|
@ -292,7 +337,9 @@ impl<S> Application<S> where S: 'static {
|
||||||
Inner {
|
Inner {
|
||||||
default: parts.default,
|
default: parts.default,
|
||||||
router: router.clone(),
|
router: router.clone(),
|
||||||
resources: resources }
|
resources: resources,
|
||||||
|
handlers: parts.handlers,
|
||||||
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
HttpApplication {
|
HttpApplication {
|
||||||
|
@ -345,8 +392,7 @@ impl<S: 'static> Iterator for Application<S> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use http::StatusCode;
|
||||||
use http::{Method, Version, Uri, HeaderMap, StatusCode};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use test::TestRequest;
|
use test::TestRequest;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
|
@ -362,18 +408,14 @@ mod tests {
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
let req = HttpRequest::new(
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
Method::GET, Uri::from_str("/blah").unwrap(),
|
|
||||||
Version::HTTP_11, HeaderMap::new(), None);
|
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
let mut app = Application::new()
|
let mut app = Application::new()
|
||||||
.default_resource(|r| r.h(httpcodes::HTTPMethodNotAllowed))
|
.default_resource(|r| r.h(httpcodes::HTTPMethodNotAllowed))
|
||||||
.finish();
|
.finish();
|
||||||
let req = HttpRequest::new(
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
Method::GET, Uri::from_str("/blah").unwrap(),
|
|
||||||
Version::HTTP_11, HeaderMap::new(), None);
|
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::METHOD_NOT_ALLOWED);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||||
}
|
}
|
||||||
|
@ -411,8 +453,40 @@ mod tests {
|
||||||
let resp = app.handle(req);
|
let resp = app.handle(req);
|
||||||
assert!(resp.is_ok());
|
assert!(resp.is_ok());
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test/blah").finish();
|
||||||
|
let resp = app.handle(req);
|
||||||
|
assert!(resp.is_ok());
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/testing").finish();
|
let req = TestRequest::with_uri("/testing").finish();
|
||||||
let resp = app.handle(req);
|
let resp = app.handle(req);
|
||||||
assert!(resp.is_err());
|
assert!(resp.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handler() {
|
||||||
|
let mut app = Application::new()
|
||||||
|
.handler("/test", httpcodes::HTTPOk)
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test/").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/test/app").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/testapp").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue