1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-30 18:44:35 +01:00

fix prefix and static file serving #168

This commit is contained in:
Nikolay Kim 2018-04-10 10:13:52 -07:00
parent bb11fb3d24
commit 81ac905c7b
3 changed files with 122 additions and 10 deletions

View File

@ -13,16 +13,18 @@
* Added `ErrorHandlers` middleware * Added `ErrorHandlers` middleware
* Router cannot parse Non-ASCII characters in URL #137 * Fix router cannot parse Non-ASCII characters in URL #137
* Fix client connection pooling
* Fix long client urls #129 * Fix long client urls #129
* Fix panic on invalid URL characters #130 * Fix panic on invalid URL characters #130
* Fix client connection pooling
* Fix logger request duration calculation #152 * Fix logger request duration calculation #152
* Fix prefix and static file serving #168
* Add `signed` and `private` `CookieSessionBackend`s * Add `signed` and `private` `CookieSessionBackend`s

View File

@ -21,6 +21,7 @@ pub type Application<S> = App<S>;
pub struct HttpApplication<S=()> { pub struct HttpApplication<S=()> {
state: Rc<S>, state: Rc<S>,
prefix: String, prefix: String,
prefix_len: usize,
router: Router, router: Router,
inner: Rc<UnsafeCell<Inner<S>>>, inner: Rc<UnsafeCell<Inner<S>>>,
middlewares: Rc<Vec<Box<Middleware<S>>>>, middlewares: Rc<Vec<Box<Middleware<S>>>>,
@ -73,6 +74,7 @@ impl<S: 'static> HttpApplication<S> {
path.len() == prefix.len() || path.len() == prefix.len() ||
path.split_at(prefix.len()).1.starts_with('/')) path.split_at(prefix.len()).1.starts_with('/'))
}; };
if m { if m {
let path: &'static str = unsafe { let path: &'static str = unsafe {
mem::transmute(&req.path()[inner.prefix+prefix.len()..]) }; mem::transmute(&req.path()[inner.prefix+prefix.len()..]) };
@ -106,8 +108,8 @@ impl<S: 'static> HttpHandler for HttpApplication<S> {
let m = { let m = {
let path = req.path(); let path = req.path();
path.starts_with(&self.prefix) && ( path.starts_with(&self.prefix) && (
path.len() == self.prefix.len() || path.len() == self.prefix_len ||
path.split_at(self.prefix.len()).1.starts_with('/')) path.split_at(self.prefix_len).1.starts_with('/'))
}; };
if m { if m {
let mut req = req.with_state(Rc::clone(&self.state), self.router.clone()); let mut req = req.with_state(Rc::clone(&self.state), self.router.clone());
@ -420,8 +422,12 @@ impl<S> App<S> where S: 'static {
pub fn handler<H: Handler<S>>(mut self, path: &str, handler: H) -> App<S> pub fn handler<H: Handler<S>>(mut self, path: &str, handler: H) -> App<S>
{ {
{ {
let path = path.trim().trim_right_matches('/').to_owned(); let mut path = path.trim().trim_right_matches('/').to_owned();
if !path.is_empty() && !path.starts_with('/') {
path.insert(0, '/')
}
let parts = self.parts.as_mut().expect("Use after finish"); let parts = self.parts.as_mut().expect("Use after finish");
parts.handlers.push((path, Box::new(WrapHandler::new(handler)))); parts.handlers.push((path, Box::new(WrapHandler::new(handler))));
} }
self self
@ -471,17 +477,22 @@ impl<S> App<S> where S: 'static {
pub fn finish(&mut self) -> HttpApplication<S> { pub fn finish(&mut self) -> HttpApplication<S> {
let parts = self.parts.take().expect("Use after finish"); let parts = self.parts.take().expect("Use after finish");
let prefix = parts.prefix.trim().trim_right_matches('/'); let prefix = parts.prefix.trim().trim_right_matches('/');
let (prefix, prefix_len) = if prefix.is_empty() {
("/".to_owned(), 0)
} else {
(prefix.to_owned(), prefix.len())
};
let mut resources = parts.resources; let mut resources = parts.resources;
for (_, pattern) in parts.external { for (_, pattern) in parts.external {
resources.push((pattern, None)); resources.push((pattern, None));
} }
let (router, resources) = Router::new(prefix, parts.settings, resources); let (router, resources) = Router::new(&prefix, parts.settings, resources);
let inner = Rc::new(UnsafeCell::new( let inner = Rc::new(UnsafeCell::new(
Inner { Inner {
prefix: prefix.len(), prefix: prefix_len,
default: parts.default, default: parts.default,
encoding: parts.encoding, encoding: parts.encoding,
handlers: parts.handlers, handlers: parts.handlers,
@ -491,9 +502,10 @@ impl<S> App<S> where S: 'static {
HttpApplication { HttpApplication {
state: Rc::new(parts.state), state: Rc::new(parts.state),
prefix: prefix.to_owned(),
router: router.clone(), router: router.clone(),
middlewares: Rc::new(parts.middlewares), middlewares: Rc::new(parts.middlewares),
prefix,
prefix_len,
inner, inner,
} }
} }
@ -670,6 +682,61 @@ mod tests {
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND); assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
} }
#[test]
fn test_handler2() {
let mut app = App::new()
.handler("test", |_| HttpResponse::Ok())
.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);
}
#[test]
fn test_handler_with_prefix() {
let mut app = App::new()
.prefix("prefix")
.handler("/test", |_| HttpResponse::Ok())
.finish();
let req = TestRequest::with_uri("/prefix/test").finish();
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
let req = TestRequest::with_uri("/prefix/test/").finish();
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
let req = TestRequest::with_uri("/prefix/test/app").finish();
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
let req = TestRequest::with_uri("/prefix/testapp").finish();
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
let req = TestRequest::with_uri("/prefix/blah").finish();
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
}
#[test] #[test]
fn test_route() { fn test_route() {
let mut app = App::new() let mut app = App::new()

View File

@ -476,6 +476,9 @@ impl<S: 'static> Handler<S> for StaticFiles<S> {
new_path.push_str(&el.to_string_lossy()); new_path.push_str(&el.to_string_lossy());
new_path.push('/'); new_path.push('/');
} }
if !new_path.ends_with('/') {
new_path.push('/');
}
new_path.push_str(redir_index); new_path.push_str(redir_index);
HttpResponse::Found() HttpResponse::Found()
.header(header::LOCATION, new_path.as_str()) .header(header::LOCATION, new_path.as_str())
@ -500,7 +503,8 @@ impl<S: 'static> Handler<S> for StaticFiles<S> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use test::TestRequest; use application::App;
use test::{self, TestRequest};
use http::{header, Method, StatusCode}; use http::{header, Method, StatusCode};
#[test] #[test]
@ -603,4 +607,43 @@ mod tests {
assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!(resp.status(), StatusCode::FOUND);
assert_eq!(resp.headers().get(header::LOCATION).unwrap(), "/examples/basics/Cargo.toml"); assert_eq!(resp.headers().get(header::LOCATION).unwrap(), "/examples/basics/Cargo.toml");
} }
#[test]
fn integration_redirect_to_index_with_prefix() {
let mut srv = test::TestServer::with_factory(
|| App::new()
.prefix("public")
.handler("/", StaticFiles::new(".").index_file("Cargo.toml")));
let request = srv.get().uri(srv.url("/public")).finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert_eq!(response.status(), StatusCode::FOUND);
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
assert_eq!(loc, "/public/Cargo.toml");
let request = srv.get().uri(srv.url("/public/")).finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert_eq!(response.status(), StatusCode::FOUND);
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
assert_eq!(loc, "/public/Cargo.toml");
}
#[test]
fn integration_redirect_to_index() {
let mut srv = test::TestServer::with_factory(
|| App::new()
.handler("test", StaticFiles::new(".").index_file("Cargo.toml")));
let request = srv.get().uri(srv.url("/test")).finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert_eq!(response.status(), StatusCode::FOUND);
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
assert_eq!(loc, "/test/Cargo.toml");
let request = srv.get().uri(srv.url("/test/")).finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert_eq!(response.status(), StatusCode::FOUND);
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
assert_eq!(loc, "/test/Cargo.toml");
}
} }