From 66c1c10d39e6ecb212ec4709888493693339c07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Sun, 24 Mar 2019 10:25:48 +0100 Subject: Implement file upload. --- src/file_upload.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/file_upload.rs (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs new file mode 100644 index 0000000..00cca17 --- /dev/null +++ b/src/file_upload.rs @@ -0,0 +1,100 @@ +use actix_web::{ + dev, error, + http::header::{ContentDisposition, LOCATION}, + multipart, Error, FutureResponse, HttpMessage, HttpRequest, HttpResponse, +}; +use std::io::Write; +use std::path::{Component, PathBuf}; + +use futures::future; +use futures::{Future, Stream}; + +pub fn save_file( + field: multipart::Field, + file_path: PathBuf, +) -> Box> { + let mut file = match std::fs::File::create(file_path) { + Ok(file) => file, + Err(e) => return Box::new(future::err(error::ErrorInternalServerError(e))), + }; + Box::new( + field + .fold(0i64, move |acc, bytes| { + let rt = file + .write_all(bytes.as_ref()) + .map(|_| acc + bytes.len() as i64) + .map_err(|e| error::MultipartError::Payload(error::PayloadError::Io(e))); + future::result(rt) + }) + .map_err(|e| error::ErrorInternalServerError(e)), + ) +} + +pub fn handle_multipart( + item: multipart::MultipartItem, + mut file_path: PathBuf, +) -> Box> { + match item { + multipart::MultipartItem::Field(field) => { + let err = || Box::new(future::err(error::ContentTypeError::ParseError.into())); + let filename = field + .headers() + .get("content-disposition") + .ok_or(err()) + .and_then(|cd| ContentDisposition::from_raw(cd).map_err(|_| err())) + .and_then(|content_disposition| { + content_disposition + .get_filename() + .ok_or(err()) + .map(|cd| String::from(cd)) + }); + 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()) + } + 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())) + .flatten(), + ), + } +} + +pub fn upload_file(req: &HttpRequest) -> FutureResponse { + if req.query().contains_key("path") { + let path_str = req.query()["path"].clone(); + let mut path = PathBuf::from(path_str.clone()); + while path.has_root() { + path = match path.strip_prefix(Component::RootDir) { + Ok(path) => path.to_path_buf(), + //TODO better error response + Err(_) => return Box::new(future::ok(HttpResponse::BadRequest().body(""))), + } + } + // TODO verify that path is under current dir + if let Ok(target_path) = path.join(req.state().path.clone()).canonicalize() { + Box::new( + req.multipart() + .map_err(error::ErrorInternalServerError) + .map(move |item| handle_multipart(item, target_path.clone())) + .flatten() + .collect() + .map(|_| { + HttpResponse::TemporaryRedirect() + .header(LOCATION, path_str) + .finish() + }) + .map_err(|e| e), + ) + } else { + Box::new(future::ok(HttpResponse::BadRequest().body(""))) + } + } else { + Box::new(future::ok(HttpResponse::BadRequest().body(""))) + } +} -- cgit v1.2.3 From f4e22946d01b3eeaec5723faa28c3ce4f6d834c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Sun, 24 Mar 2019 19:57:37 +0100 Subject: Check if file path is under app root dir. --- src/file_upload.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index 00cca17..442b47c 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -69,15 +69,28 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< if req.query().contains_key("path") { let path_str = req.query()["path"].clone(); let mut path = PathBuf::from(path_str.clone()); - while path.has_root() { + // serever root path should be valid + let app_root_dir = req.state().path.clone().canonicalize().unwrap(); + // allow file upload only under current dir + if path.has_root() { path = match path.strip_prefix(Component::RootDir) { - Ok(path) => path.to_path_buf(), - //TODO better error response - Err(_) => return Box::new(future::ok(HttpResponse::BadRequest().body(""))), + Ok(dir) => dir.to_path_buf(), + Err(_) => { + return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))) + } } } - // TODO verify that path is under current dir - if let Ok(target_path) = path.join(req.state().path.clone()).canonicalize() { + let target_dir = match app_root_dir.clone().join(path).canonicalize() { + Ok(path) => { + if path.starts_with(&app_root_dir) { + path + } else { + return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))); + } + } + Err(_) => return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))), + }; + if let Ok(target_path) = target_dir.canonicalize() { Box::new( req.multipart() .map_err(error::ErrorInternalServerError) @@ -92,7 +105,7 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< .map_err(|e| e), ) } else { - Box::new(future::ok(HttpResponse::BadRequest().body(""))) + Box::new(future::ok(HttpResponse::BadRequest().body("invalid path"))) } } else { Box::new(future::ok(HttpResponse::BadRequest().body(""))) -- cgit v1.2.3 From ea0323de8c90bf96ff46a84db069e8b81f994759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Mon, 25 Mar 2019 14:23:01 +0100 Subject: Refactoring --- src/file_upload.rs | 84 +++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 48 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index 442b47c..f72ab8b 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -3,11 +3,11 @@ use actix_web::{ http::header::{ContentDisposition, LOCATION}, multipart, Error, FutureResponse, HttpMessage, HttpRequest, HttpResponse, }; -use std::io::Write; -use std::path::{Component, PathBuf}; - -use futures::future; -use futures::{Future, Stream}; +use futures::{future, Future, Stream}; +use std::{ + io::Write, + path::{Component, PathBuf}, +}; pub fn save_file( field: multipart::Field, @@ -66,48 +66,36 @@ pub fn handle_multipart( } pub fn upload_file(req: &HttpRequest) -> FutureResponse { - if req.query().contains_key("path") { - let path_str = req.query()["path"].clone(); - let mut path = PathBuf::from(path_str.clone()); - // serever root path should be valid - let app_root_dir = req.state().path.clone().canonicalize().unwrap(); - // allow file upload only under current dir - if path.has_root() { - path = match path.strip_prefix(Component::RootDir) { - Ok(dir) => dir.to_path_buf(), - Err(_) => { - return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))) - } - } - } - let target_dir = match app_root_dir.clone().join(path).canonicalize() { - Ok(path) => { - if path.starts_with(&app_root_dir) { - path - } else { - return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))); - } - } - Err(_) => return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))), - }; - if let Ok(target_path) = target_dir.canonicalize() { - Box::new( - req.multipart() - .map_err(error::ErrorInternalServerError) - .map(move |item| handle_multipart(item, target_path.clone())) - .flatten() - .collect() - .map(|_| { - HttpResponse::TemporaryRedirect() - .header(LOCATION, path_str) - .finish() - }) - .map_err(|e| e), - ) - } else { - Box::new(future::ok(HttpResponse::BadRequest().body("invalid path"))) - } - } else { - Box::new(future::ok(HttpResponse::BadRequest().body(""))) + if !req.query().contains_key("path") { + return Box::new(future::ok( + HttpResponse::BadRequest().body("Unspecified parameter path"), + )); } + // server root path should be valid so we can unwrap it + let app_root_dir = req.state().path.clone().canonicalize().unwrap(); + + let path_str = req.query()["path"].clone(); + let mut path = PathBuf::from(path_str.clone()); + if let Ok(stripped_path) = path.strip_prefix(Component::RootDir) { + path = stripped_path.to_owned(); + } + + // if target path is under app root directory save file + let target_dir = match &app_root_dir.clone().join(path).canonicalize() { + Ok(path) if path.starts_with(&app_root_dir) => path.clone(), + _ => return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))), + }; + Box::new( + req.multipart() + .map_err(error::ErrorInternalServerError) + .map(move |item| handle_multipart(item, target_dir.clone())) + .flatten() + .collect() + .map(|_| { + HttpResponse::TemporaryRedirect() + .header(LOCATION, path_str) + .finish() + }) + .map_err(|e| e), + ) } -- cgit v1.2.3 From 1e8783e23c3c5e64acc40464329b64e3de6e2a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Mon, 25 Mar 2019 14:44:45 +0100 Subject: Document file upload. --- src/file_upload.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index f72ab8b..c0ec95f 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -9,7 +9,8 @@ use std::{ path::{Component, PathBuf}, }; -pub fn save_file( +/// Create future to save file. +fn save_file( field: multipart::Field, file_path: PathBuf, ) -> Box> { @@ -30,7 +31,8 @@ pub fn save_file( ) } -pub fn handle_multipart( +/// Create new future to handle file as multipart data. +fn handle_multipart( item: multipart::MultipartItem, mut file_path: PathBuf, ) -> Box> { @@ -65,6 +67,11 @@ pub fn handle_multipart( } } +/// Handle incoming request to upload file. +/// Target file path is expected as path parameter in URI and is interpreted as relative from +/// server root directory. Any path which will go outside of this directory is considered +/// invalid. +/// This method returns future. pub fn upload_file(req: &HttpRequest) -> FutureResponse { if !req.query().contains_key("path") { return Box::new(future::ok( -- cgit v1.2.3 From c6e5fef650e6b9e286f9d918e3cb730372d78892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Tue, 26 Mar 2019 21:38:57 +0100 Subject: Use proper typed query param. --- src/file_upload.rs | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index c0ec95f..dd4c962 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -1,14 +1,21 @@ use actix_web::{ dev, error, http::header::{ContentDisposition, LOCATION}, - multipart, Error, FutureResponse, HttpMessage, HttpRequest, HttpResponse, + multipart, Error, FromRequest, FutureResponse, HttpMessage, HttpRequest, HttpResponse, Query, }; use futures::{future, Future, Stream}; +use serde::Deserialize; use std::{ io::Write, path::{Component, PathBuf}, }; +/// Query parameters +#[derive(Debug, Deserialize)] +struct QueryParameters { + path: PathBuf, +} + /// Create future to save file. fn save_file( field: multipart::Field, @@ -73,22 +80,24 @@ fn handle_multipart( /// invalid. /// This method returns future. pub fn upload_file(req: &HttpRequest) -> FutureResponse { - if !req.query().contains_key("path") { - return Box::new(future::ok( - HttpResponse::BadRequest().body("Unspecified parameter path"), - )); - } - // server root path should be valid so we can unwrap it let app_root_dir = req.state().path.clone().canonicalize().unwrap(); - - let path_str = req.query()["path"].clone(); - let mut path = PathBuf::from(path_str.clone()); - if let Ok(stripped_path) = path.strip_prefix(Component::RootDir) { - path = stripped_path.to_owned(); - } + let path = match Query::::extract(req) { + Ok(query) => { + if let Ok(stripped_path) = query.path.strip_prefix(Component::RootDir) { + stripped_path.to_owned() + } else { + query.path.clone() + } + } + Err(_) => { + return Box::new(future::ok( + HttpResponse::BadRequest().body("Unspecified parameter path"), + )) + } + }; // if target path is under app root directory save file - let target_dir = match &app_root_dir.clone().join(path).canonicalize() { + let target_dir = match &app_root_dir.clone().join(path.clone()).canonicalize() { Ok(path) if path.starts_with(&app_root_dir) => path.clone(), _ => return Box::new(future::ok(HttpResponse::BadRequest().body("Invalid path"))), }; @@ -98,9 +107,9 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< .map(move |item| handle_multipart(item, target_dir.clone())) .flatten() .collect() - .map(|_| { + .map(move |_| { HttpResponse::TemporaryRedirect() - .header(LOCATION, path_str) + .header(LOCATION, format!("{}", path.display())) .finish() }) .map_err(|e| e), -- cgit v1.2.3 From d14e17d94964291fda976423c1fe1a772d5af60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Wed, 27 Mar 2019 09:44:29 +0100 Subject: Add CLI arguments for file uploading. --- src/file_upload.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/file_upload.rs') 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, file_path: PathBuf, + override_files: bool, ) -> Box> { + 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, mut file_path: PathBuf, + override_files: bool, ) -> Box> { 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) -> 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 |_| { -- cgit v1.2.3 From 84b5852aad17961dfa2cb6ea3351b9fa3244fe6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Thu, 28 Mar 2019 11:29:56 +0100 Subject: Fix file upload when used with random route. --- src/file_upload.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index 9f87724..98e3680 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -1,6 +1,6 @@ use actix_web::{ dev, error, - http::header::{ContentDisposition, LOCATION}, + http::header::{ContentDisposition, LOCATION, REFERER}, multipart, Error, FromRequest, FutureResponse, HttpMessage, HttpRequest, HttpResponse, Query, }; use futures::{future, Future, Stream}; @@ -99,6 +99,7 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< )) } }; + let return_path = req.headers()[REFERER].clone(); // if target path is under app root directory save file let target_dir = match &app_root_dir.clone().join(path.clone()).canonicalize() { @@ -112,9 +113,10 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< .map(move |item| handle_multipart(item, target_dir.clone(), override_files)) .flatten() .collect() + //.map(|s| HttpResponse::Ok().json(s)) .map(move |_| { HttpResponse::TemporaryRedirect() - .header(LOCATION, format!("{}", path.display())) + .header(LOCATION, format!("{}", return_path.to_str().unwrap_or("/"))) .finish() }) .map_err(|e| e), -- cgit v1.2.3 From e2ad04f4139d0f0aceb02c43b6913d17d11087ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Thu, 28 Mar 2019 18:32:15 +0100 Subject: Better error handling for file upload. --- src/file_upload.rs | 55 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 22 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index 98e3680..02478c6 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -1,7 +1,8 @@ +use crate::errors::FileUploadErrorKind; +use crate::renderer::file_upload_error; use actix_web::{ - dev, error, - http::header::{ContentDisposition, LOCATION, REFERER}, - multipart, Error, FromRequest, FutureResponse, HttpMessage, HttpRequest, HttpResponse, Query, + dev, http::header, multipart, FromRequest, FutureResponse, HttpMessage, HttpRequest, + HttpResponse, Query, }; use futures::{future, Future, Stream}; use serde::Deserialize; @@ -21,24 +22,26 @@ fn save_file( field: multipart::Field, file_path: PathBuf, override_files: bool, -) -> Box> { +) -> Box> { if !override_files && file_path.exists() { - return Box::new(future::err(error::ErrorInternalServerError("file exists"))); + return Box::new(future::err(FileUploadErrorKind::FileExist)); } let mut file = match std::fs::File::create(file_path) { Ok(file) => file, - Err(e) => return Box::new(future::err(error::ErrorInternalServerError(e))), + Err(e) => { + return Box::new(future::err(FileUploadErrorKind::IOError(e))); + } }; Box::new( field + .map_err(|e| FileUploadErrorKind::MultipartError(e)) .fold(0i64, move |acc, bytes| { let rt = file .write_all(bytes.as_ref()) .map(|_| acc + bytes.len() as i64) - .map_err(|e| error::MultipartError::Payload(error::PayloadError::Io(e))); + .map_err(|e| FileUploadErrorKind::IOError(e)); future::result(rt) - }) - .map_err(|e| error::ErrorInternalServerError(e)), + }), ) } @@ -47,19 +50,21 @@ fn handle_multipart( item: multipart::MultipartItem, mut file_path: PathBuf, override_files: bool, -) -> Box> { +) -> Box> { match item { multipart::MultipartItem::Field(field) => { - let err = || Box::new(future::err(error::ContentTypeError::ParseError.into())); let filename = field .headers() - .get("content-disposition") - .ok_or(err()) - .and_then(|cd| ContentDisposition::from_raw(cd).map_err(|_| err())) + .get(header::CONTENT_DISPOSITION) + .ok_or(FileUploadErrorKind::ParseError) + .and_then(|cd| { + header::ContentDisposition::from_raw(cd) + .map_err(|_| FileUploadErrorKind::ParseError) + }) .and_then(|content_disposition| { content_disposition .get_filename() - .ok_or(err()) + .ok_or(FileUploadErrorKind::ParseError) .map(|cd| String::from(cd)) }); match filename { @@ -67,11 +72,11 @@ fn handle_multipart( file_path = file_path.join(f); Box::new(save_file(field, file_path, override_files).into_stream()) } - Err(e) => Box::new(e.into_stream()), + Err(e) => Box::new(future::err(e).into_stream()), } } multipart::MultipartItem::Nested(mp) => Box::new( - mp.map_err(error::ErrorInternalServerError) + mp.map_err(|e| FileUploadErrorKind::MultipartError(e)) .map(move |item| handle_multipart(item, file_path.clone(), override_files)) .flatten(), ), @@ -99,7 +104,9 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< )) } }; - let return_path = req.headers()[REFERER].clone(); + // this is really ugly I will try to think about something smarter + let return_path: String = req.headers()[header::REFERER].clone().to_str().unwrap_or("/").to_owned(); + let r_p2 = return_path.clone(); // if target path is under app root directory save file let target_dir = match &app_root_dir.clone().join(path.clone()).canonicalize() { @@ -109,16 +116,20 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< let override_files = req.state().override_files; Box::new( req.multipart() - .map_err(error::ErrorInternalServerError) + .map_err(|e| FileUploadErrorKind::MultipartError(e)) .map(move |item| handle_multipart(item, target_dir.clone(), override_files)) .flatten() .collect() - //.map(|s| HttpResponse::Ok().json(s)) .map(move |_| { HttpResponse::TemporaryRedirect() - .header(LOCATION, format!("{}", return_path.to_str().unwrap_or("/"))) + .header( + header::LOCATION, + format!("{}", return_path.clone()), + ) .finish() }) - .map_err(|e| e), + .or_else(move |e| { + let error_description = format!("{}",e); + future::ok(HttpResponse::BadRequest().body(file_upload_error(&error_description, &r_p2.clone()).into_string())) ) } -- cgit v1.2.3 From a13b26c1c90707056e5d4e36d67563fc91467871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Thu, 28 Mar 2019 18:49:17 +0100 Subject: Check if we have permissions to create files. --- src/file_upload.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index 02478c6..bc4efb1 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -7,6 +7,7 @@ use actix_web::{ use futures::{future, Future, Stream}; use serde::Deserialize; use std::{ + fs, io::Write, path::{Component, PathBuf}, }; @@ -67,12 +68,23 @@ fn handle_multipart( .ok_or(FileUploadErrorKind::ParseError) .map(|cd| String::from(cd)) }); + let err = |e: FileUploadErrorKind| Box::new(future::err(e).into_stream()); match filename { Ok(f) => { + match fs::metadata(&file_path) { + Ok(metadata) => { + if !metadata.is_dir() || metadata.permissions().readonly() { + return err(FileUploadErrorKind::InsufficientPermissions); + } + } + Err(_) => { + return err(FileUploadErrorKind::InsufficientPermissions); + } + } file_path = file_path.join(f); Box::new(save_file(field, file_path, override_files).into_stream()) } - Err(e) => Box::new(future::err(e).into_stream()), + Err(e) => err(e), } } multipart::MultipartItem::Nested(mp) => Box::new( -- cgit v1.2.3 From 8f3d5b70416e9275fdd0953181dee3bd6c6b0c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Fri, 29 Mar 2019 17:47:33 +0100 Subject: Fix syntax error and clippy warnings. --- src/file_upload.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index bc4efb1..88b8802 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -35,12 +35,12 @@ fn save_file( }; Box::new( field - .map_err(|e| FileUploadErrorKind::MultipartError(e)) + .map_err(FileUploadErrorKind::MultipartError) .fold(0i64, move |acc, bytes| { let rt = file .write_all(bytes.as_ref()) .map(|_| acc + bytes.len() as i64) - .map_err(|e| FileUploadErrorKind::IOError(e)); + .map_err(FileUploadErrorKind::IOError); future::result(rt) }), ) @@ -66,7 +66,7 @@ fn handle_multipart( content_disposition .get_filename() .ok_or(FileUploadErrorKind::ParseError) - .map(|cd| String::from(cd)) + .map(String::from) }); let err = |e: FileUploadErrorKind| Box::new(future::err(e).into_stream()); match filename { @@ -88,7 +88,7 @@ fn handle_multipart( } } multipart::MultipartItem::Nested(mp) => Box::new( - mp.map_err(|e| FileUploadErrorKind::MultipartError(e)) + mp.map_err(FileUploadErrorKind::MultipartError) .map(move |item| handle_multipart(item, file_path.clone(), override_files)) .flatten(), ), @@ -117,7 +117,11 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< } }; // this is really ugly I will try to think about something smarter - let return_path: String = req.headers()[header::REFERER].clone().to_str().unwrap_or("/").to_owned(); + let return_path: String = req.headers()[header::REFERER] + .clone() + .to_str() + .unwrap_or("/") + .to_owned(); let r_p2 = return_path.clone(); // if target path is under app root directory save file @@ -128,20 +132,21 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< let override_files = req.state().override_files; Box::new( req.multipart() - .map_err(|e| FileUploadErrorKind::MultipartError(e)) + .map_err(FileUploadErrorKind::MultipartError) .map(move |item| handle_multipart(item, target_dir.clone(), override_files)) .flatten() .collect() .map(move |_| { HttpResponse::TemporaryRedirect() - .header( - header::LOCATION, - format!("{}", return_path.clone()), - ) + .header(header::LOCATION, return_path.to_string()) .finish() }) .or_else(move |e| { - let error_description = format!("{}",e); - future::ok(HttpResponse::BadRequest().body(file_upload_error(&error_description, &r_p2.clone()).into_string())) + let error_description = format!("{}", e); + future::ok( + HttpResponse::BadRequest() + .body(file_upload_error(&error_description, &r_p2.clone()).into_string()), + ) + }), ) } -- cgit v1.2.3 From 93ea625fe29ea02c5bda6b4f6361134a0fe667f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Pej=C5=A1a?= Date: Fri, 29 Mar 2019 23:33:27 +0100 Subject: Fix typos and indentation. --- src/file_upload.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/file_upload.rs') diff --git a/src/file_upload.rs b/src/file_upload.rs index 88b8802..273d12c 100644 --- a/src/file_upload.rs +++ b/src/file_upload.rs @@ -22,9 +22,9 @@ struct QueryParameters { fn save_file( field: multipart::Field, file_path: PathBuf, - override_files: bool, + overwrite_files: bool, ) -> Box> { - if !override_files && file_path.exists() { + if !overwrite_files && file_path.exists() { return Box::new(future::err(FileUploadErrorKind::FileExist)); } let mut file = match std::fs::File::create(file_path) { @@ -50,7 +50,7 @@ fn save_file( fn handle_multipart( item: multipart::MultipartItem, mut file_path: PathBuf, - override_files: bool, + overwrite_files: bool, ) -> Box> { match item { multipart::MultipartItem::Field(field) => { @@ -82,14 +82,14 @@ fn handle_multipart( } } file_path = file_path.join(f); - Box::new(save_file(field, file_path, override_files).into_stream()) + Box::new(save_file(field, file_path, overwrite_files).into_stream()) } Err(e) => err(e), } } multipart::MultipartItem::Nested(mp) => Box::new( mp.map_err(FileUploadErrorKind::MultipartError) - .map(move |item| handle_multipart(item, file_path.clone(), override_files)) + .map(move |item| handle_multipart(item, file_path.clone(), overwrite_files)) .flatten(), ), } @@ -124,16 +124,16 @@ pub fn upload_file(req: &HttpRequest) -> FutureResponse< .to_owned(); let r_p2 = return_path.clone(); - // if target path is under app root directory save file + // If the target path is under the app root directory, save the file. let target_dir = match &app_root_dir.clone().join(path.clone()).canonicalize() { 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; + let overwrite_files = req.state().overwrite_files; Box::new( req.multipart() .map_err(FileUploadErrorKind::MultipartError) - .map(move |item| handle_multipart(item, target_dir.clone(), override_files)) + .map(move |item| handle_multipart(item, target_dir.clone(), overwrite_files)) .flatten() .collect() .map(move |_| { -- cgit v1.2.3