1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-27 17:52:56 +01:00

Handling scoped paths without leading slashes #460

This commit is contained in:
Nikolay Kim 2018-09-02 08:14:54 -07:00
parent d5957a8466
commit 968c81e267
3 changed files with 71 additions and 20 deletions

View File

@ -1,6 +1,6 @@
# Changes
## [0.7.5] - 2018-09-xx
## [0.7.5] - 2018-09-02
### Added
@ -13,6 +13,8 @@
* Handle socket read disconnect
* Handling scoped paths without leading slashes #460
## [0.7.4] - 2018-08-23

View File

@ -183,7 +183,7 @@ impl<S: 'static> Scope<S> {
where
F: FnOnce(Scope<S>) -> Scope<S>,
{
let rdef = ResourceDef::prefix(&path);
let rdef = ResourceDef::prefix(&insert_slash(path));
let scope = Scope {
rdef: rdef.clone(),
filters: Vec::new(),
@ -230,9 +230,11 @@ impl<S: 'static> Scope<S> {
R: Responder + 'static,
T: FromRequest<S> + 'static,
{
Rc::get_mut(&mut self.router)
.unwrap()
.register_route(path, method, f);
Rc::get_mut(&mut self.router).unwrap().register_route(
&insert_slash(path),
method,
f,
);
self
}
@ -264,7 +266,7 @@ impl<S: 'static> Scope<S> {
F: FnOnce(&mut Resource<S>) -> R + 'static,
{
// add resource
let mut resource = Resource::new(ResourceDef::new(path));
let mut resource = Resource::new(ResourceDef::new(&insert_slash(path)));
f(&mut resource);
Rc::get_mut(&mut self.router)
@ -311,7 +313,6 @@ impl<S: 'static> Scope<S> {
/// }
/// ```
pub fn handler<H: Handler<S>>(mut self, path: &str, handler: H) -> Scope<S> {
{
let mut path = path.trim().trim_right_matches('/').to_owned();
if !path.is_empty() && !path.starts_with('/') {
path.insert(0, '/')
@ -323,7 +324,6 @@ impl<S: 'static> Scope<S> {
Rc::get_mut(&mut self.router)
.expect("Multiple copies of scope router")
.register_handler(&path, Box::new(WrapHandler::new(handler)), None);
}
self
}
@ -342,6 +342,14 @@ impl<S: 'static> Scope<S> {
}
}
fn insert_slash(path: &str) -> String {
let mut path = path.to_owned();
if !path.is_empty() && !path.starts_with('/') {
path.insert(0, '/');
};
path
}
impl<S: 'static> RouteHandler<S> for Scope<S> {
fn handle(&self, req: &HttpRequest<S>) -> AsyncResult<HttpResponse> {
let tail = req.match_info().tail as usize;
@ -844,6 +852,34 @@ mod tests {
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
}
#[test]
fn test_scope_route_without_leading_slash() {
let app = App::new()
.scope("app", |scope| {
scope
.route("path1", Method::GET, |_: HttpRequest<_>| HttpResponse::Ok())
.route("path1", Method::DELETE, |_: HttpRequest<_>| {
HttpResponse::Ok()
})
}).finish();
let req = TestRequest::with_uri("/app/path1").request();
let resp = app.run(req);
assert_eq!(resp.as_msg().status(), StatusCode::OK);
let req = TestRequest::with_uri("/app/path1")
.method(Method::DELETE)
.request();
let resp = app.run(req);
assert_eq!(resp.as_msg().status(), StatusCode::OK);
let req = TestRequest::with_uri("/app/path1")
.method(Method::POST)
.request();
let resp = app.run(req);
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
}
#[test]
fn test_scope_filter() {
let app = App::new()
@ -1013,6 +1049,20 @@ mod tests {
assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
}
#[test]
fn test_nested_scope_no_slash() {
let app = App::new()
.scope("/app", |scope| {
scope.nested("t1", |scope| {
scope.resource("/path1", |r| r.f(|_| HttpResponse::Created()))
})
}).finish();
let req = TestRequest::with_uri("/app/t1/path1").request();
let resp = app.run(req);
assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
}
#[test]
fn test_nested_scope_root() {
let app = App::new()

View File

@ -948,8 +948,7 @@ fn test_default_404_handler_response() {
tokio::io::write_all(sock, "HEAD / HTTP/1.1\r\nHost: localhost\r\n\r\n")
.and_then(|(sock, _)| tokio::io::read_exact(sock, &mut buf))
.and_then(|(_, buf)| Ok(buf))
})
.map_err(|e| panic!("{:?}", e));
}).map_err(|e| panic!("{:?}", e));
let response = srv.execute(request).unwrap();
let rep = String::from_utf8_lossy(&response[..]);
assert!(rep.contains("HTTP/1.1 404 Not Found"));