diff options
Diffstat (limited to '')
-rw-r--r-- | src/errors.rs | 17 | ||||
-rw-r--r-- | src/file_upload.rs | 55 | ||||
-rw-r--r-- | src/renderer.rs | 11 |
3 files changed, 61 insertions, 22 deletions
diff --git a/src/errors.rs b/src/errors.rs index 2aa5f58..f42cc02 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,23 @@ use failure::{Backtrace, Context, Fail}; use std::fmt::{self, Debug, Display}; +/// Kinds of errors which might happen during file upload +#[derive(Debug, Fail)] +pub enum FileUploadErrorKind { + /// This error will occur when file overriding is off and file with same name already exists + #[fail(display = "File with this name already exists")] + FileExist, + /// This error will occur when server will fail to preccess http header during file upload + #[fail(display = "Failed to parse incoming request")] + ParseError, + /// This error will occur when we fail to precess multipart request + #[fail(display = "Failed to process multipart request")] + MultipartError(actix_web::error::MultipartError), + /// This error may occur when trying to write incoming file to disk + #[fail(display = "Failed to create or write to file")] + IOError(std::io::Error), +} + /// Kinds of errors which might happen during the generation of an archive #[derive(Debug, Fail)] pub enum CompressionErrorKind { 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<dev::Payload>, file_path: PathBuf, override_files: bool, -) -> Box<Future<Item = i64, Error = Error>> { +) -> Box<Future<Item = i64, Error = FileUploadErrorKind>> { 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<dev::Payload>, mut file_path: PathBuf, override_files: bool, -) -> Box<Stream<Item = i64, Error = Error>> { +) -> Box<Stream<Item = i64, Error = FileUploadErrorKind>> { 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<crate::MiniserveConfig>) -> 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<crate::MiniserveConfig>) -> 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())) ) } diff --git a/src/renderer.rs b/src/renderer.rs index 0a9f42b..75d5c56 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -390,3 +390,14 @@ fn humanize_systemtime(src_time: Option<SystemTime>) -> Option<String> { .and_then(|from_now| Duration::from_std(from_now).ok()) .map(|duration| HumanTime::from(duration).to_text_en(Accuracy::Rough, Tense::Past)) } + +/// Renders error page when file uploading fails +pub fn file_upload_error(error_description: &str, return_address: &str) -> Markup { + html! { + h1 { "File uploading failed" } + p { (error_description) } + a href=(return_address) { + "back" + } + } +} |