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:
Damjan Georgievski 2018-07-22 05:36:45 +02:00
parent 8a86739f14
commit 1a12b3aa30
2 changed files with 22 additions and 16 deletions

View file

@ -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()));
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();
let sys = actix::System::new("http_server_rs");
let directory = String::from(chdir);
server::new(move || web::create_app(&directory))
info!("Serving files from {:?}", root);
server::new(move || web::create_app(&root))
.bind(&bind_addr)
.expect(&format!("Can't listen on {} ", bind_addr))
.start();
info!("Serving files from {}", chdir);
let _ = sys.run();
Ok(())
}

View file

@ -1,4 +1,5 @@
use actix_web::{error, fs, App, HttpRequest, HttpResponse, Responder, middleware};
use actix_web::dev::FromParam;
use futures::Stream;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use htmlescape::encode_minimal as escape_html_entity;
@ -9,9 +10,12 @@ use std::path::PathBuf;
use std;
use bytes;
pub fn create_app(directory: &str) -> App {
let static_files = fs::StaticFiles::new(directory).unwrap().show_files_listing().files_listing_renderer(handle_directory);
App::new()
pub fn create_app(directory: &PathBuf) -> App<PathBuf> {
let root = directory.to_path_buf();
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"#))
.resource(r"/{tail:.*}.tar", |r| r.get().f(handle_tar))
.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>(
dir: &'a fs::Directory,
req: &'b HttpRequest,
req: &'b HttpRequest<PathBuf>,
) -> std::io::Result<HttpResponse> {
let mut paths: Vec<_> = std::fs::read_dir(&dir.path).unwrap()
.filter_map(|entry| if dir.is_visible(&entry) { entry.ok() } else {None})
.collect();
.filter_map(|entry| if dir.is_visible(&entry) { entry.ok() } else {None})
.collect();
paths.sort_by_key(|r| (!r.metadata().unwrap().file_type().is_dir(), r.file_name()));
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>
@ -61,19 +65,23 @@ fn handle_directory<'a, 'b>(
Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html))
}
fn handle_tar(req: &HttpRequest) -> impl Responder {
let path: PathBuf = req.match_info().query("tail")?;
if !(path.is_dir()) {
fn handle_tar(req: &HttpRequest<PathBuf>) -> impl Responder {
let root = req.state();
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"));
}
let stream = channel::stream_tar_in_thread(path);
let stream = channel::stream_tar_in_thread(fullpath);
let resp = HttpResponse::Ok()
.content_type("application/x-tar")
.streaming(stream.map_err(|_e| error::ErrorBadRequest("stream error")));
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"))
}