mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-27 17:52:56 +01:00
fix prefix and static file serving #168
This commit is contained in:
parent
bb11fb3d24
commit
81ac905c7b
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
45
src/fs.rs
45
src/fs.rs
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user