canonicalized root directory is now also an App state
- used to setup the StaticFiles handler - also for the .tar file handler additionally, PathBuf::from_param is used to forbid certain paths, see: https://actix.rs/api/actix-web/stable/actix_web/dev/trait.FromParam.html
This commit is contained in:
parent
8a86739f14
commit
1a12b3aa30
2 changed files with 22 additions and 16 deletions
|
@ -47,19 +47,17 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
std::env::set_var("RUST_LOG", std::env::var("RUST_LOG").unwrap_or("info".to_string()));
|
std::env::set_var("RUST_LOG", std::env::var("RUST_LOG").unwrap_or("info".to_string()));
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let root = std::path::Path::new(&chdir);
|
let root = std::path::PathBuf::from(chdir).canonicalize()?;
|
||||||
std::env::set_current_dir(&root).unwrap();
|
std::env::set_current_dir(&root).unwrap();
|
||||||
|
|
||||||
let sys = actix::System::new("http_server_rs");
|
let sys = actix::System::new("http_server_rs");
|
||||||
|
|
||||||
let directory = String::from(chdir);
|
info!("Serving files from {:?}", root);
|
||||||
server::new(move || web::create_app(&directory))
|
server::new(move || web::create_app(&root))
|
||||||
.bind(&bind_addr)
|
.bind(&bind_addr)
|
||||||
.expect(&format!("Can't listen on {} ", bind_addr))
|
.expect(&format!("Can't listen on {} ", bind_addr))
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
info!("Serving files from {}", chdir);
|
|
||||||
|
|
||||||
let _ = sys.run();
|
let _ = sys.run();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
30
src/web.rs
30
src/web.rs
|
@ -1,4 +1,5 @@
|
||||||
use actix_web::{error, fs, App, HttpRequest, HttpResponse, Responder, middleware};
|
use actix_web::{error, fs, App, HttpRequest, HttpResponse, Responder, middleware};
|
||||||
|
use actix_web::dev::FromParam;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
|
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
|
||||||
use htmlescape::encode_minimal as escape_html_entity;
|
use htmlescape::encode_minimal as escape_html_entity;
|
||||||
|
@ -9,9 +10,12 @@ use std::path::PathBuf;
|
||||||
use std;
|
use std;
|
||||||
use bytes;
|
use bytes;
|
||||||
|
|
||||||
pub fn create_app(directory: &str) -> App {
|
pub fn create_app(directory: &PathBuf) -> App<PathBuf> {
|
||||||
let static_files = fs::StaticFiles::new(directory).unwrap().show_files_listing().files_listing_renderer(handle_directory);
|
let root = directory.to_path_buf();
|
||||||
App::new()
|
let static_files = fs::StaticFiles::new(&root).unwrap()
|
||||||
|
.show_files_listing()
|
||||||
|
.files_listing_renderer(handle_directory);
|
||||||
|
App::with_state(root)
|
||||||
.middleware(middleware::Logger::new(r#"%a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T"#))
|
.middleware(middleware::Logger::new(r#"%a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T"#))
|
||||||
.resource(r"/{tail:.*}.tar", |r| r.get().f(handle_tar))
|
.resource(r"/{tail:.*}.tar", |r| r.get().f(handle_tar))
|
||||||
.resource(r"/favicon.ico", |r| r.get().f(favicon_ico))
|
.resource(r"/favicon.ico", |r| r.get().f(favicon_ico))
|
||||||
|
@ -20,12 +24,12 @@ pub fn create_app(directory: &str) -> App {
|
||||||
|
|
||||||
fn handle_directory<'a, 'b>(
|
fn handle_directory<'a, 'b>(
|
||||||
dir: &'a fs::Directory,
|
dir: &'a fs::Directory,
|
||||||
req: &'b HttpRequest,
|
req: &'b HttpRequest<PathBuf>,
|
||||||
) -> std::io::Result<HttpResponse> {
|
) -> std::io::Result<HttpResponse> {
|
||||||
|
|
||||||
let mut paths: Vec<_> = std::fs::read_dir(&dir.path).unwrap()
|
let mut paths: Vec<_> = std::fs::read_dir(&dir.path).unwrap()
|
||||||
.filter_map(|entry| if dir.is_visible(&entry) { entry.ok() } else {None})
|
.filter_map(|entry| if dir.is_visible(&entry) { entry.ok() } else {None})
|
||||||
.collect();
|
.collect();
|
||||||
paths.sort_by_key(|r| (!r.metadata().unwrap().file_type().is_dir(), r.file_name()));
|
paths.sort_by_key(|r| (!r.metadata().unwrap().file_type().is_dir(), r.file_name()));
|
||||||
let mut body = String::new();
|
let mut body = String::new();
|
||||||
body.push_str(&format!("<h1>Index of {index}</h1><small>[<a href={index}.tar>.tar</a> of whole directory]</small><hr>
|
body.push_str(&format!("<h1>Index of {index}</h1><small>[<a href={index}.tar>.tar</a> of whole directory]</small><hr>
|
||||||
|
@ -61,19 +65,23 @@ fn handle_directory<'a, 'b>(
|
||||||
Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html))
|
Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_tar(req: &HttpRequest) -> impl Responder {
|
fn handle_tar(req: &HttpRequest<PathBuf>) -> impl Responder {
|
||||||
let path: PathBuf = req.match_info().query("tail")?;
|
let root = req.state();
|
||||||
if !(path.is_dir()) {
|
let tail: String = req.match_info().query("tail")?;
|
||||||
|
let relpath = PathBuf::from_param(tail.trim_left_matches('/'))?;
|
||||||
|
let fullpath = root.join(&relpath).canonicalize()?;
|
||||||
|
|
||||||
|
if !(fullpath.is_dir()) {
|
||||||
return Err(error::ErrorBadRequest("not a directory"));
|
return Err(error::ErrorBadRequest("not a directory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream = channel::stream_tar_in_thread(path);
|
let stream = channel::stream_tar_in_thread(fullpath);
|
||||||
let resp = HttpResponse::Ok()
|
let resp = HttpResponse::Ok()
|
||||||
.content_type("application/x-tar")
|
.content_type("application/x-tar")
|
||||||
.streaming(stream.map_err(|_e| error::ErrorBadRequest("stream error")));
|
.streaming(stream.map_err(|_e| error::ErrorBadRequest("stream error")));
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn favicon_ico(_req: &HttpRequest) -> impl Responder {
|
fn favicon_ico(_req: &HttpRequest<PathBuf>) -> impl Responder {
|
||||||
bytes::Bytes::from_static(include_bytes!("favicon.png"))
|
bytes::Bytes::from_static(include_bytes!("favicon.png"))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue