diff options
author | Vojtěch Pejša <vojtechpejsa7@gmail.com> | 2019-03-27 08:44:29 +0000 |
---|---|---|
committer | Vojtěch Pejša <vojtechpejsa7@gmail.com> | 2019-04-04 08:51:00 +0000 |
commit | d14e17d94964291fda976423c1fe1a772d5af60b (patch) | |
tree | 0515e663527bd59fc74e2649e185ee1fbcda785a | |
parent | Use proper typed query param. (diff) | |
download | miniserve-d14e17d94964291fda976423c1fe1a772d5af60b.tar.gz miniserve-d14e17d94964291fda976423c1fe1a772d5af60b.zip |
Add CLI arguments for file uploading.
-rw-r--r-- | src/args.rs | 10 | ||||
-rw-r--r-- | src/file_upload.rs | 13 | ||||
-rw-r--r-- | src/listing.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 25 | ||||
-rw-r--r-- | src/renderer.rs | 3 |
5 files changed, 44 insertions, 9 deletions
diff --git a/src/args.rs b/src/args.rs index 4f0dbf7..7fa5121 100644 --- a/src/args.rs +++ b/src/args.rs @@ -47,6 +47,14 @@ struct CLIArgs { /// Do not follow symbolic links #[structopt(short = "P", long = "no-symlinks")] no_symlinks: bool, + + /// Enable file uploading + #[structopt(short = "u", long = "upload-files")] + file_upload: bool, + + /// Enable overriding existing files during file upload + #[structopt(short = "o", long = "owerride-files")] + override_files: bool, } /// Checks wether an interface is valid, i.e. it can be parsed into an IP address @@ -100,5 +108,7 @@ pub fn parse_args() -> crate::MiniserveConfig { path_explicitly_chosen, no_symlinks: args.no_symlinks, random_route, + override_files: args.override_files, + file_upload: args.file_upload, } } diff --git a/src/file_upload.rs b/src/file_upload.rs index dd4c962..9f87724 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -20,7 +20,11 @@ struct QueryParameters { fn save_file( field: multipart::Field<dev::Payload>, file_path: PathBuf, + override_files: bool, ) -> Box<Future<Item = i64, Error = Error>> { + if !override_files && file_path.exists() { + return Box::new(future::err(error::ErrorInternalServerError("file exists"))); + } let mut file = match std::fs::File::create(file_path) { Ok(file) => file, Err(e) => return Box::new(future::err(error::ErrorInternalServerError(e))), @@ -42,6 +46,7 @@ fn save_file( fn handle_multipart( item: multipart::MultipartItem<dev::Payload>, mut file_path: PathBuf, + override_files: bool, ) -> Box<Stream<Item = i64, Error = Error>> { match item { multipart::MultipartItem::Field(field) => { @@ -60,15 +65,14 @@ fn handle_multipart( match filename { Ok(f) => { file_path = file_path.join(f); - // TODO should I allow overriding existing files? - Box::new(save_file(field, file_path).into_stream()) + Box::new(save_file(field, file_path, override_files).into_stream()) } Err(e) => Box::new(e.into_stream()), } } multipart::MultipartItem::Nested(mp) => Box::new( mp.map_err(error::ErrorInternalServerError) - .map(move |item| handle_multipart(item, file_path.clone())) + .map(move |item| handle_multipart(item, file_path.clone(), override_files)) .flatten(), ), } @@ -101,10 +105,11 @@ pub fn upload_file(req: &HttpRequest<crate::MiniserveConfig>) -> FutureResponse< Ok(path) if path.starts_with(&app_root_dir) => path.clone(), _ => return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))), }; + let override_files = req.state().override_files; Box::new( req.multipart() .map_err(error::ErrorInternalServerError) - .map(move |item| handle_multipart(item, target_dir.clone())) + .map(move |item| handle_multipart(item, target_dir.clone(), override_files)) .flatten() .collect() .map(move |_| { diff --git a/src/listing.rs b/src/listing.rs index 0173176..5fde879 100644 --- a/src/listing.rs +++ b/src/listing.rs @@ -130,6 +130,7 @@ pub fn directory_listing<S>( dir: &fs::Directory, req: &HttpRequest<S>, skip_symlinks: bool, + file_upload: bool, random_route: Option<String>, ) -> Result<HttpResponse, io::Error> { let title = format!("Index of {}", req.path()); @@ -265,6 +266,7 @@ pub fn directory_listing<S>( page_parent, sort_method, sort_order, + file_upload, &base.to_string_lossy(), ) .into_string(), diff --git a/src/main.rs b/src/main.rs index fb7e321..f7d0b1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,12 @@ pub struct MiniserveConfig { /// Enable random route generation pub random_route: Option<String>, + + /// Enable file upload + pub file_upload: bool, + + /// Enable upload to override existing files + pub override_files: bool, } fn main() { @@ -175,11 +181,12 @@ fn main() { } /// Configures the Actix application -fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> { +fn configure_app(mut app: App<MiniserveConfig>) -> App<MiniserveConfig> { let s = { let path = &app.state().path; let no_symlinks = app.state().no_symlinks; let random_route = app.state().random_route.clone(); + let file_upload = app.state().file_upload.clone(); if path.is_file() { None } else { @@ -188,7 +195,13 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> { .expect("Couldn't create path") .show_files_listing() .files_listing_renderer(move |dir, req| { - listing::directory_listing(dir, req, no_symlinks, random_route.clone()) + listing::directory_listing( + dir, + req, + no_symlinks, + file_upload, + random_route.clone(), + ) }), ) } @@ -198,9 +211,11 @@ fn configure_app(app: App<MiniserveConfig>) -> App<MiniserveConfig> { let full_route = format!("/{}", random_route); // Allow file upload - let app = app.resource("/upload", |r| { - r.method(Method::POST).f(file_upload::upload_file) - }); + if app.state().file_upload { + app = app.resource("/upload", |r| { + r.method(Method::POST).f(file_upload::upload_file) + }); + } if let Some(s) = s { // Handle directories diff --git a/src/renderer.rs b/src/renderer.rs index 3039dc7..6b3fb9f 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -14,6 +14,7 @@ pub fn page( page_parent: Option<String>, sort_method: Option<listing::SortingMethod>, sort_order: Option<listing::SortingOrder>, + file_upload: bool, base: &str, ) -> Markup { html! { @@ -21,11 +22,13 @@ pub fn page( body { span #top { } h1 { (page_title) } + @if file_upload { form action={"/upload?path=" (base)} method="POST" enctype="multipart/form-data" { p { "Select file to upload" } input type="file" name="file_to_upload" {} input type="submit" value="Upload file" {} } + } div.download { (archive_button(archive::CompressionMethod::TarGz)) } |