mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-30 18:34:36 +01:00
Allow to override files listing renderer for #203
This commit is contained in:
parent
35a4078434
commit
32a2866449
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
* Allow to access Error's backtrace object
|
* Allow to access Error's backtrace object
|
||||||
|
|
||||||
|
* Allow to override files listing renderer for `StaticFiles` #203
|
||||||
|
|
||||||
* Various extractor usability improvements #207
|
* Various extractor usability improvements #207
|
||||||
|
|
||||||
|
|
||||||
|
120
src/fs.rs
120
src/fs.rs
@ -365,11 +365,14 @@ impl Stream for ChunkedReadFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DirectoryRenderer<S> =
|
||||||
|
Fn(&Directory, &HttpRequest<S>) -> Result<HttpResponse, io::Error>;
|
||||||
|
|
||||||
/// A directory; responds with the generated directory listing.
|
/// A directory; responds with the generated directory listing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Directory {
|
pub struct Directory {
|
||||||
base: PathBuf,
|
pub base: PathBuf,
|
||||||
path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Directory {
|
impl Directory {
|
||||||
@ -377,7 +380,7 @@ impl Directory {
|
|||||||
Directory { base, path }
|
Directory { base, path }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_list(&self, entry: &io::Result<DirEntry>) -> bool {
|
pub fn is_visible(&self, entry: &io::Result<DirEntry>) -> bool {
|
||||||
if let Ok(ref entry) = *entry {
|
if let Ok(ref entry) = *entry {
|
||||||
if let Some(name) = entry.file_name().to_str() {
|
if let Some(name) = entry.file_name().to_str() {
|
||||||
if name.starts_with('.') {
|
if name.starts_with('.') {
|
||||||
@ -393,61 +396,58 @@ impl Directory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for Directory {
|
fn directory_listing<S>(
|
||||||
type Item = HttpResponse;
|
dir: &Directory, req: &HttpRequest<S>,
|
||||||
type Error = io::Error;
|
) -> Result<HttpResponse, io::Error> {
|
||||||
|
let index_of = format!("Index of {}", req.path());
|
||||||
|
let mut body = String::new();
|
||||||
|
let base = Path::new(req.path());
|
||||||
|
|
||||||
fn respond_to(self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
|
for entry in dir.path.read_dir()? {
|
||||||
let index_of = format!("Index of {}", req.path());
|
if dir.is_visible(&entry) {
|
||||||
let mut body = String::new();
|
let entry = entry.unwrap();
|
||||||
let base = Path::new(req.path());
|
let p = match entry.path().strip_prefix(&dir.path) {
|
||||||
|
Ok(p) => base.join(p),
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
// show file url as relative to static path
|
||||||
|
let file_url = format!("{}", p.to_string_lossy());
|
||||||
|
|
||||||
for entry in self.path.read_dir()? {
|
// if file is a directory, add '/' to the end of the name
|
||||||
if self.can_list(&entry) {
|
if let Ok(metadata) = entry.metadata() {
|
||||||
let entry = entry.unwrap();
|
if metadata.is_dir() {
|
||||||
let p = match entry.path().strip_prefix(&self.path) {
|
let _ = write!(
|
||||||
Ok(p) => base.join(p),
|
body,
|
||||||
Err(_) => continue,
|
"<li><a href=\"{}\">{}/</a></li>",
|
||||||
};
|
file_url,
|
||||||
// show file url as relative to static path
|
entry.file_name().to_string_lossy()
|
||||||
let file_url = format!("{}", p.to_string_lossy());
|
);
|
||||||
|
|
||||||
// if file is a directory, add '/' to the end of the name
|
|
||||||
if let Ok(metadata) = entry.metadata() {
|
|
||||||
if metadata.is_dir() {
|
|
||||||
let _ = write!(
|
|
||||||
body,
|
|
||||||
"<li><a href=\"{}\">{}/</a></li>",
|
|
||||||
file_url,
|
|
||||||
entry.file_name().to_string_lossy()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let _ = write!(
|
|
||||||
body,
|
|
||||||
"<li><a href=\"{}\">{}</a></li>",
|
|
||||||
file_url,
|
|
||||||
entry.file_name().to_string_lossy()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
continue;
|
let _ = write!(
|
||||||
|
body,
|
||||||
|
"<li><a href=\"{}\">{}</a></li>",
|
||||||
|
file_url,
|
||||||
|
entry.file_name().to_string_lossy()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let html = format!(
|
|
||||||
"<html>\
|
|
||||||
<head><title>{}</title></head>\
|
|
||||||
<body><h1>{}</h1>\
|
|
||||||
<ul>\
|
|
||||||
{}\
|
|
||||||
</ul></body>\n</html>",
|
|
||||||
index_of, index_of, body
|
|
||||||
);
|
|
||||||
Ok(HttpResponse::Ok()
|
|
||||||
.content_type("text/html; charset=utf-8")
|
|
||||||
.body(html))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let html = format!(
|
||||||
|
"<html>\
|
||||||
|
<head><title>{}</title></head>\
|
||||||
|
<body><h1>{}</h1>\
|
||||||
|
<ul>\
|
||||||
|
{}\
|
||||||
|
</ul></body>\n</html>",
|
||||||
|
index_of, index_of, body
|
||||||
|
);
|
||||||
|
Ok(HttpResponse::Ok()
|
||||||
|
.content_type("text/html; charset=utf-8")
|
||||||
|
.body(html))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Static files handling
|
/// Static files handling
|
||||||
@ -472,6 +472,7 @@ pub struct StaticFiles<S> {
|
|||||||
show_index: bool,
|
show_index: bool,
|
||||||
cpu_pool: CpuPool,
|
cpu_pool: CpuPool,
|
||||||
default: Box<RouteHandler<S>>,
|
default: Box<RouteHandler<S>>,
|
||||||
|
renderer: Box<DirectoryRenderer<S>>,
|
||||||
_chunk_size: usize,
|
_chunk_size: usize,
|
||||||
_follow_symlinks: bool,
|
_follow_symlinks: bool,
|
||||||
}
|
}
|
||||||
@ -535,6 +536,7 @@ impl<S: 'static> StaticFiles<S> {
|
|||||||
default: Box::new(WrapHandler::new(|_| {
|
default: Box::new(WrapHandler::new(|_| {
|
||||||
HttpResponse::new(StatusCode::NOT_FOUND)
|
HttpResponse::new(StatusCode::NOT_FOUND)
|
||||||
})),
|
})),
|
||||||
|
renderer: Box::new(directory_listing),
|
||||||
_chunk_size: 0,
|
_chunk_size: 0,
|
||||||
_follow_symlinks: false,
|
_follow_symlinks: false,
|
||||||
}
|
}
|
||||||
@ -548,6 +550,17 @@ impl<S: 'static> StaticFiles<S> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set custom directory renderer
|
||||||
|
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
|
||||||
|
where
|
||||||
|
for<'r, 's> F: Fn(&'r Directory, &'s HttpRequest<S>)
|
||||||
|
-> Result<HttpResponse, io::Error>
|
||||||
|
+ 'static,
|
||||||
|
{
|
||||||
|
self.renderer = Box::new(f);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set index file
|
/// Set index file
|
||||||
///
|
///
|
||||||
/// Redirects to specific index file for directory "/" instead of
|
/// Redirects to specific index file for directory "/" instead of
|
||||||
@ -601,9 +614,8 @@ impl<S: 'static> Handler<S> for StaticFiles<S> {
|
|||||||
.finish()
|
.finish()
|
||||||
.respond_to(req.drop_state())
|
.respond_to(req.drop_state())
|
||||||
} else if self.show_index {
|
} else if self.show_index {
|
||||||
Directory::new(self.directory.clone(), path)
|
let dir = Directory::new(self.directory.clone(), path);
|
||||||
.respond_to(req.drop_state())?
|
Ok((*self.renderer)(&dir, &req)?.into())
|
||||||
.respond_to(req.drop_state())
|
|
||||||
} else {
|
} else {
|
||||||
Ok(self.default.handle(req))
|
Ok(self.default.handle(req))
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ pub use self::logger::Logger;
|
|||||||
|
|
||||||
/// Middleware start result
|
/// Middleware start result
|
||||||
pub enum Started {
|
pub enum Started {
|
||||||
/// Execution completed
|
/// Middleware is completed, continue to next middleware
|
||||||
Done,
|
Done,
|
||||||
/// New http response got generated. If middleware generates response
|
/// New http response got generated. If middleware generates response
|
||||||
/// handler execution halts.
|
/// handler execution halts.
|
||||||
|
Loading…
Reference in New Issue
Block a user