mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 01:32:57 +01:00
handle application prefix for handlers; use handler for StaticFiles
This commit is contained in:
parent
77ba1de305
commit
f0fdcc9936
@ -25,9 +25,8 @@ fn main() {
|
|||||||
## Directory
|
## Directory
|
||||||
|
|
||||||
To serve files from specific directory and sub-directories `StaticFiles` could be used.
|
To serve files from specific directory and sub-directories `StaticFiles` could be used.
|
||||||
`StaticFiles` could be registered with `Application::resource` method.
|
`StaticFiles` must be registered with `Application::handler()` method otherwise
|
||||||
`StaticFiles` requires tail named path expression for resource registration.
|
it won't be able to server sub-paths.
|
||||||
And this name has to be used in `StaticFile` constructor.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate actix_web;
|
# extern crate actix_web;
|
||||||
@ -35,12 +34,11 @@ use actix_web::*;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new()
|
Application::new()
|
||||||
.resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
|
.handler("/static", fs::StaticFiles::new(".", true))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
First parameter is a name of path pattern. Second parameter is a base directory.
|
First parameter is a base directory. Second parameter is *show_index*, if it is set to *true*
|
||||||
Third parameter is *show_index*, if it is set to *true*
|
|
||||||
directory listing would be returned for directories, if it is set to *false*
|
directory listing would be returned for directories, if it is set to *false*
|
||||||
then *404 Not Found* would be returned instead of directory listing.
|
then *404 Not Found* would be returned instead of directory listing.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -22,6 +23,7 @@ pub struct HttpApplication<S=()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Inner<S> {
|
pub(crate) struct Inner<S> {
|
||||||
|
prefix: usize,
|
||||||
default: Resource<S>,
|
default: Resource<S>,
|
||||||
router: Router,
|
router: Router,
|
||||||
resources: Vec<Resource<S>>,
|
resources: Vec<Resource<S>>,
|
||||||
@ -36,12 +38,18 @@ impl<S: 'static> PipelineHandler<S> for Inner<S> {
|
|||||||
} else {
|
} else {
|
||||||
for &mut (ref prefix, ref mut handler) in &mut self.handlers {
|
for &mut (ref prefix, ref mut handler) in &mut self.handlers {
|
||||||
let m = {
|
let m = {
|
||||||
let path = req.path();
|
let path = &req.path()[self.prefix..];
|
||||||
path.starts_with(prefix) && (
|
path.starts_with(prefix) && (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{
|
||||||
|
mem::transmute(&req.path()[self.prefix+prefix.len()..])};
|
||||||
|
if path.is_empty() {
|
||||||
|
req.match_info_mut().add("tail", "");
|
||||||
|
} else {
|
||||||
|
req.match_info_mut().add("tail", path.trim_left_matches('/'));
|
||||||
|
}
|
||||||
return handler.handle(req)
|
return handler.handle(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,6 +343,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
|
|
||||||
let inner = Rc::new(RefCell::new(
|
let inner = Rc::new(RefCell::new(
|
||||||
Inner {
|
Inner {
|
||||||
|
prefix: prefix.len(),
|
||||||
default: parts.default,
|
default: parts.default,
|
||||||
router: router.clone(),
|
router: router.clone(),
|
||||||
resources: resources,
|
resources: resources,
|
||||||
@ -487,6 +496,39 @@ mod tests {
|
|||||||
let req = TestRequest::with_uri("/blah").finish();
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handler_prefix() {
|
||||||
|
let mut app = Application::new()
|
||||||
|
.prefix("/app")
|
||||||
|
.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::NOT_FOUND);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/test").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/test/").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/test/app").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/testapp").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/blah").finish();
|
||||||
|
let resp = app.run(req);
|
||||||
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
14
src/fs.rs
14
src/fs.rs
@ -191,8 +191,8 @@ impl Responder for FilesystemElement {
|
|||||||
|
|
||||||
/// Static files handling
|
/// Static files handling
|
||||||
///
|
///
|
||||||
/// Can be registered with `Application::resource()`. Resource path has to contain
|
/// `StaticFile` handler must be registered with `Application::handler()` method,
|
||||||
/// tail named pattern and this name has to be used in `StaticFile` constructor.
|
/// because `StaticFile` handler requires access sub-path information.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
@ -200,12 +200,11 @@ impl Responder for FilesystemElement {
|
|||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new()
|
/// let app = Application::new()
|
||||||
/// .resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
|
/// .handler("/static", fs::StaticFiles::new(".", true))
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct StaticFiles {
|
pub struct StaticFiles {
|
||||||
name: String,
|
|
||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
accessible: bool,
|
accessible: bool,
|
||||||
show_index: bool,
|
show_index: bool,
|
||||||
@ -219,7 +218,7 @@ impl StaticFiles {
|
|||||||
/// `dir` - base directory
|
/// `dir` - base directory
|
||||||
///
|
///
|
||||||
/// `index` - show index for directory
|
/// `index` - show index for directory
|
||||||
pub fn new<D: Into<PathBuf>>(name: &str, dir: D, index: bool) -> StaticFiles {
|
pub fn new<D: Into<PathBuf>>(dir: D, index: bool) -> StaticFiles {
|
||||||
let dir = dir.into();
|
let dir = dir.into();
|
||||||
|
|
||||||
let (dir, access) = match dir.canonicalize() {
|
let (dir, access) = match dir.canonicalize() {
|
||||||
@ -238,7 +237,6 @@ impl StaticFiles {
|
|||||||
};
|
};
|
||||||
|
|
||||||
StaticFiles {
|
StaticFiles {
|
||||||
name: name.to_owned(),
|
|
||||||
directory: dir,
|
directory: dir,
|
||||||
accessible: access,
|
accessible: access,
|
||||||
show_index: index,
|
show_index: index,
|
||||||
@ -256,7 +254,7 @@ impl<S> Handler<S> for StaticFiles {
|
|||||||
if !self.accessible {
|
if !self.accessible {
|
||||||
Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
|
Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
|
||||||
} else {
|
} else {
|
||||||
let path = if let Some(path) = req.match_info().get(&self.name) {
|
let path = if let Some(path) = req.match_info().get("tail") {
|
||||||
path
|
path
|
||||||
} else {
|
} else {
|
||||||
return Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
|
return Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
|
||||||
@ -300,7 +298,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_static_files() {
|
fn test_static_files() {
|
||||||
let mut st = StaticFiles::new("tail", ".", true);
|
let mut st = StaticFiles::new(".", true);
|
||||||
st.accessible = false;
|
st.accessible = false;
|
||||||
assert!(st.handle(HttpRequest::default()).is_err());
|
assert!(st.handle(HttpRequest::default()).is_err());
|
||||||
|
|
||||||
|
@ -677,7 +677,14 @@ impl<S, H> ProcessResponse<S, H> {
|
|||||||
// response is completed
|
// response is completed
|
||||||
match self.iostate {
|
match self.iostate {
|
||||||
IOState::Done => {
|
IOState::Done => {
|
||||||
io.write_eof();
|
match io.write_eof() {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => {
|
||||||
|
debug!("Error sending data: {}", err);
|
||||||
|
info.error = Some(err.into());
|
||||||
|
return Ok(FinishingMiddlewares::init(info, self.resp))
|
||||||
|
}
|
||||||
|
}
|
||||||
self.resp.set_response_size(io.written());
|
self.resp.set_response_size(io.written());
|
||||||
Ok(FinishingMiddlewares::init(info, self.resp))
|
Ok(FinishingMiddlewares::init(info, self.resp))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user