aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/archive.rs55
-rw-r--r--src/args.rs18
-rw-r--r--src/auth.rs13
-rw-r--r--src/errors.rs63
-rw-r--r--src/file_upload.rs47
-rw-r--r--src/main.rs41
6 files changed, 67 insertions, 170 deletions
diff --git a/src/archive.rs b/src/archive.rs
index b5788f5..02300c5 100644
--- a/src/archive.rs
+++ b/src/archive.rs
@@ -7,7 +7,7 @@ use std::path::PathBuf;
use strum_macros::{Display, EnumIter, EnumString};
use tar::Builder;
-use crate::errors::{ContextualError, ContextualErrorKind};
+use crate::errors::ContextualError;
/// Available compression methods
#[derive(Deserialize, Clone, EnumIter, EnumString, Display)]
@@ -62,17 +62,11 @@ fn tgz_compress(dir: &PathBuf, skip_symlinks: bool) -> Result<(String, Bytes), C
let mut tgz_data = Bytes::new();
let tar_data = tar(src_dir, directory.to_string(), skip_symlinks).map_err(|e| {
- ContextualError::new(ContextualErrorKind::ArchiveCreationError(
- "tarball".to_string(),
- Box::new(e),
- ))
+ ContextualError::ArchiveCreationError("tarball".to_string(), Box::new(e))
})?;
let gz_data = gzip(&tar_data).map_err(|e| {
- ContextualError::new(ContextualErrorKind::ArchiveCreationError(
- "GZIP archive".to_string(),
- Box::new(e),
- ))
+ ContextualError::ArchiveCreationError("GZIP archive".to_string(), Box::new(e))
})?;
tgz_data.extend_from_slice(&gz_data);
@@ -80,15 +74,15 @@ fn tgz_compress(dir: &PathBuf, skip_symlinks: bool) -> Result<(String, Bytes), C
Ok((dst_tgz_filename, tgz_data))
} else {
// https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_str
- Err(ContextualError::new(ContextualErrorKind::InvalidPathError(
+ Err(ContextualError::InvalidPathError(
"Directory name contains invalid UTF-8 characters".to_string(),
- )))
+ ))
}
} else {
// https://doc.rust-lang.org/std/path/struct.Path.html#method.file_name
- Err(ContextualError::new(ContextualErrorKind::InvalidPathError(
+ Err(ContextualError::InvalidPathError(
"Directory name terminates in \"..\"".to_string(),
- )))
+ ))
}
}
@@ -105,20 +99,17 @@ fn tar(
tar_builder
.append_dir_all(inner_folder, &src_dir)
.map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
+ ContextualError::IOError(
format!(
"Failed to append the content of {} to the TAR archive",
&src_dir
),
e,
- ))
+ )
})?;
let tar_content = tar_builder.into_inner().map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to finish writing the TAR archive".to_string(),
- e,
- ))
+ ContextualError::IOError("Failed to finish writing the TAR archive".to_string(), e)
})?;
Ok(tar_content)
@@ -126,24 +117,14 @@ fn tar(
/// Compresses a stream of bytes using the GZIP algorithm, and returns the resulting stream
fn gzip(mut data: &[u8]) -> Result<Vec<u8>, ContextualError> {
- let mut encoder = Encoder::new(Vec::new()).map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to create GZIP encoder".to_string(),
- e,
- ))
- })?;
- io::copy(&mut data, &mut encoder).map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to write GZIP data".to_string(),
- e,
- ))
- })?;
- let data = encoder.finish().into_result().map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to write GZIP trailer".to_string(),
- e,
- ))
- })?;
+ let mut encoder = Encoder::new(Vec::new())
+ .map_err(|e| ContextualError::IOError("Failed to create GZIP encoder".to_string(), e))?;
+ io::copy(&mut data, &mut encoder)
+ .map_err(|e| ContextualError::IOError("Failed to write GZIP data".to_string(), e))?;
+ let data = encoder
+ .finish()
+ .into_result()
+ .map_err(|e| ContextualError::IOError("Failed to write GZIP trailer".to_string(), e))?;
Ok(data)
}
diff --git a/src/args.rs b/src/args.rs
index 9ccb7a6..d37e429 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -3,7 +3,7 @@ use std::path::PathBuf;
use structopt::StructOpt;
use crate::auth;
-use crate::errors::{ContextualError, ContextualErrorKind};
+use crate::errors::ContextualError;
use crate::themes;
/// Possible characters for random routes
@@ -80,7 +80,7 @@ fn parse_interface(src: &str) -> Result<IpAddr, std::net::AddrParseError> {
/// Checks wether the auth string is valid, i.e. it follows the syntax username:password
fn parse_auth(src: &str) -> Result<auth::RequiredAuth, ContextualError> {
let mut split = src.splitn(3, ':');
- let invalid_auth_format = Err(ContextualError::new(ContextualErrorKind::InvalidAuthFormat));
+ let invalid_auth_format = Err(ContextualError::InvalidAuthFormat);
let username = match split.next() {
Some(username) => username,
@@ -98,28 +98,20 @@ fn parse_auth(src: &str) -> Result<auth::RequiredAuth, ContextualError> {
let hash_bin = if let Ok(hash_bin) = hex::decode(hash_hex) {
hash_bin
} else {
- return Err(ContextualError::new(
- ContextualErrorKind::InvalidPasswordHash,
- ));
+ return Err(ContextualError::InvalidPasswordHash);
};
match second_part {
"sha256" => auth::RequiredAuthPassword::Sha256(hash_bin.to_owned()),
"sha512" => auth::RequiredAuthPassword::Sha512(hash_bin.to_owned()),
- _ => {
- return Err(ContextualError::new(
- ContextualErrorKind::InvalidHashMethod(second_part.to_owned()),
- ))
- }
+ _ => return Err(ContextualError::InvalidHashMethod(second_part.to_owned())),
}
} else {
// To make it Windows-compatible, the password needs to be shorter than 255 characters.
// After 255 characters, Windows will truncate the value.
// As for the username, the spec does not mention a limit in length
if second_part.len() > 255 {
- return Err(ContextualError::new(
- ContextualErrorKind::PasswordTooLongError,
- ));
+ return Err(ContextualError::PasswordTooLongError);
}
auth::RequiredAuthPassword::Plain(second_part.to_owned())
diff --git a/src/auth.rs b/src/auth.rs
index a42bb53..c786d4b 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -3,7 +3,7 @@ use actix_web::middleware::{Middleware, Response};
use actix_web::{HttpRequest, HttpResponse, Result};
use sha2::{Digest, Sha256, Sha512};
-use crate::errors::{ContextualError, ContextualErrorKind};
+use crate::errors::ContextualError;
pub struct Auth;
@@ -36,13 +36,10 @@ pub fn parse_basic_auth(
let basic_removed = authorization_header
.to_str()
.map_err(|e| {
- ContextualError::new(ContextualErrorKind::ParseError(
- "HTTP authentication header".to_string(),
- e.to_string(),
- ))
+ ContextualError::ParseError("HTTP authentication header".to_string(), e.to_string())
})?
.replace("Basic ", "");
- let decoded = base64::decode(&basic_removed).map_err(ContextualErrorKind::Base64DecodeError)?;
+ let decoded = base64::decode(&basic_removed).map_err(ContextualError::Base64DecodeError)?;
let decoded_str = String::from_utf8_lossy(&decoded);
let credentials: Vec<&str> = decoded_str.splitn(2, ':').collect();
@@ -97,9 +94,7 @@ impl Middleware<crate::MiniserveConfig> for Auth {
let auth_req = match parse_basic_auth(auth_headers) {
Ok(auth_req) => auth_req,
Err(err) => {
- let auth_err = ContextualError::new(
- ContextualErrorKind::HTTPAuthenticationError(Box::new(err)),
- );
+ let auth_err = ContextualError::HTTPAuthenticationError(Box::new(err));
return Ok(Response::Done(
HttpResponse::BadRequest().body(auth_err.to_string()),
));
diff --git a/src/errors.rs b/src/errors.rs
index bf45b73..8264de0 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,8 +1,7 @@
-use failure::{Backtrace, Context, Fail};
-use std::fmt::{self, Debug, Display};
+use failure::Fail;
#[derive(Debug, Fail)]
-pub enum ContextualErrorKind {
+pub enum ContextualError {
/// Fully customized errors, not inheriting from any error
#[fail(display = "{}", _0)]
CustomError(String),
@@ -33,10 +32,7 @@ pub enum ContextualErrorKind {
InvalidAuthFormat,
/// This error might occure if the hash method is neither sha256 nor sha512
- #[fail(
- display = "Invalid hashing method {}. Expected sha256 or sha512",
- _0
- )]
+ #[fail(display = "Invalid hashing method {}. Expected sha256 or sha512", _0)]
InvalidHashMethod(String),
/// This error might occur if the HTTP auth hash password is not a valid hex code
@@ -80,58 +76,9 @@ pub fn log_error_chain(description: String) {
}
}
-/// Based on https://boats.gitlab.io/failure/error-errorkind.html
-pub struct ContextualError {
- inner: Context<ContextualErrorKind>,
-}
-
-impl ContextualError {
- pub fn new(kind: ContextualErrorKind) -> ContextualError {
- ContextualError {
- inner: Context::new(kind),
- }
- }
-}
-
-impl Fail for ContextualError {
- fn cause(&self) -> Option<&Fail> {
- self.inner.cause()
- }
-
- fn backtrace(&self) -> Option<&Backtrace> {
- self.inner.backtrace()
- }
-}
-
-impl Display for ContextualError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Display::fmt(&self.inner, f)
- }
-}
-
-impl Debug for ContextualError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Debug::fmt(&self.inner, f)
- }
-}
-
-impl From<Context<ContextualErrorKind>> for ContextualError {
- fn from(inner: Context<ContextualErrorKind>) -> ContextualError {
- ContextualError { inner }
- }
-}
-
-impl From<ContextualErrorKind> for ContextualError {
- fn from(kind: ContextualErrorKind) -> ContextualError {
- ContextualError {
- inner: Context::new(kind),
- }
- }
-}
-
-/// This allows to create CustomErrors more simply
+/// This makes creating CustomErrors easier
impl From<String> for ContextualError {
fn from(msg: String) -> ContextualError {
- ContextualError::new(ContextualErrorKind::CustomError(msg))
+ ContextualError::CustomError(msg)
}
}
diff --git a/src/file_upload.rs b/src/file_upload.rs
index f8c5019..46a3a1f 100644
--- a/src/file_upload.rs
+++ b/src/file_upload.rs
@@ -9,7 +9,7 @@ use std::{
path::{Component, PathBuf},
};
-use crate::errors::{self, ContextualError, ContextualErrorKind};
+use crate::errors::{self, ContextualError};
use crate::listing::{QueryParameters, SortingMethod, SortingOrder};
use crate::renderer;
use crate::themes::ColorScheme;
@@ -19,9 +19,9 @@ fn save_file(
field: multipart::Field<dev::Payload>,
file_path: PathBuf,
overwrite_files: bool,
-) -> Box<Future<Item = i64, Error = ContextualErrorKind>> {
+) -> Box<Future<Item = i64, Error = ContextualError>> {
if !overwrite_files && file_path.exists() {
- return Box::new(future::err(ContextualErrorKind::CustomError(
+ return Box::new(future::err(ContextualError::CustomError(
"File already exists, and the overwrite_files option has not been set".to_string(),
)));
}
@@ -29,7 +29,7 @@ fn save_file(
let mut file = match std::fs::File::create(&file_path) {
Ok(file) => file,
Err(e) => {
- return Box::new(future::err(ContextualErrorKind::IOError(
+ return Box::new(future::err(ContextualError::IOError(
format!("Failed to create {}", file_path.display()),
e,
)));
@@ -37,13 +37,13 @@ fn save_file(
};
Box::new(
field
- .map_err(ContextualErrorKind::MultipartError)
+ .map_err(ContextualError::MultipartError)
.fold(0i64, move |acc, bytes| {
let rt = file
.write_all(bytes.as_ref())
.map(|_| acc + bytes.len() as i64)
.map_err(|e| {
- ContextualErrorKind::IOError("Failed to write to file".to_string(), e)
+ ContextualError::IOError("Failed to write to file".to_string(), e)
});
future::result(rt)
}),
@@ -55,41 +55,41 @@ fn handle_multipart(
item: multipart::MultipartItem<dev::Payload>,
mut file_path: PathBuf,
overwrite_files: bool,
-) -> Box<Stream<Item = i64, Error = ContextualErrorKind>> {
+) -> Box<Stream<Item = i64, Error = ContextualError>> {
match item {
multipart::MultipartItem::Field(field) => {
let filename = field
.headers()
.get(header::CONTENT_DISPOSITION)
- .ok_or(ContextualErrorKind::ParseError)
+ .ok_or(ContextualError::ParseError)
.and_then(|cd| {
header::ContentDisposition::from_raw(cd)
- .map_err(|_| ContextualErrorKind::ParseError)
+ .map_err(|_| ContextualError::ParseError)
})
.and_then(|content_disposition| {
content_disposition
.get_filename()
- .ok_or(ContextualErrorKind::ParseError)
+ .ok_or(ContextualError::ParseError)
.map(String::from)
});
- let err = |e: ContextualErrorKind| Box::new(future::err(e).into_stream());
+ let err = |e: ContextualError| Box::new(future::err(e).into_stream());
match filename {
Ok(f) => {
match fs::metadata(&file_path) {
Ok(metadata) => {
if !metadata.is_dir() {
- return err(ContextualErrorKind::InvalidPathError(format!(
+ return err(ContextualError::InvalidPathError(format!(
"cannot upload file to {}, since it's not a directory",
&file_path.display()
)));
} else if metadata.permissions().readonly() {
- return err(ContextualErrorKind::InsufficientPermissionsError(
+ return err(ContextualError::InsufficientPermissionsError(
file_path.display().to_string(),
));
}
}
Err(_) => {
- return err(ContextualErrorKind::InsufficientPermissionsError(
+ return err(ContextualError::InsufficientPermissionsError(
file_path.display().to_string(),
));
}
@@ -104,7 +104,7 @@ fn handle_multipart(
}
}
multipart::MultipartItem::Nested(mp) => Box::new(
- mp.map_err(ContextualErrorKind::MultipartError)
+ mp.map_err(ContextualError::MultipartError)
.map(move |item| handle_multipart(item, file_path.clone(), overwrite_files))
.flatten(),
),
@@ -145,9 +145,9 @@ pub fn upload_file(
(path.clone(), sort_param, order_param, theme_param)
}
} else {
- let err = ContextualError::new(ContextualErrorKind::InvalidHTTPRequestError(
+ let err = ContextualError::InvalidHTTPRequestError(
"Missing query parameter 'path'".to_string(),
- ));
+ );
return Box::new(create_error_response(
&err.to_string(),
&return_path,
@@ -159,8 +159,7 @@ pub fn upload_file(
}
}
Err(e) => {
- let err =
- ContextualError::new(ContextualErrorKind::InvalidHTTPRequestError(e.to_string()));
+ let err = ContextualError::InvalidHTTPRequestError(e.to_string());
return Box::new(create_error_response(
&err.to_string(),
&return_path,
@@ -175,10 +174,10 @@ pub fn upload_file(
let app_root_dir = match req.state().path.canonicalize() {
Ok(dir) => dir,
Err(e) => {
- let err = ContextualError::new(ContextualErrorKind::IOError(
+ let err = ContextualError::IOError(
"Failed to resolve path served by miniserve".to_string(),
e,
- ));
+ );
return Box::new(create_error_response(
&err.to_string(),
&return_path,
@@ -194,9 +193,9 @@ pub fn upload_file(
let target_dir = match &app_root_dir.clone().join(path).canonicalize() {
Ok(path) if path.starts_with(&app_root_dir) => path.clone(),
_ => {
- let err = ContextualError::new(ContextualErrorKind::InvalidHTTPRequestError(
+ let err = ContextualError::InvalidHTTPRequestError(
"Invalid value for 'path' parameter".to_string(),
- ));
+ );
return Box::new(create_error_response(
&err.to_string(),
&return_path,
@@ -210,7 +209,7 @@ pub fn upload_file(
let overwrite_files = req.state().overwrite_files;
Box::new(
req.multipart()
- .map_err(ContextualErrorKind::MultipartError)
+ .map_err(ContextualError::MultipartError)
.map(move |item| handle_multipart(item, target_dir.clone(), overwrite_files))
.flatten()
.collect()
diff --git a/src/main.rs b/src/main.rs
index bd71763..c5c81f2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -19,7 +19,7 @@ mod listing;
mod renderer;
mod themes;
-use crate::errors::{ContextualError, ContextualErrorKind};
+use crate::errors::ContextualError;
#[derive(Clone)]
/// Configuration of the Miniserve application
@@ -84,10 +84,7 @@ fn run() -> Result<(), ContextualError> {
.path
.symlink_metadata()
.map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to retrieve symlink's metadata".to_string(),
- e,
- ))
+ ContextualError::IOError("Failed to retrieve symlink's metadata".to_string(), e)
})?
.file_type()
.is_symlink()
@@ -117,10 +114,7 @@ fn run() -> Result<(), ContextualError> {
.collect::<Vec<String>>();
let canon_path = miniserve_config.path.canonicalize().map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to resolve path to be served".to_string(),
- e,
- ))
+ ContextualError::IOError("Failed to resolve path to be served".to_string(), e)
})?;
let path_string = canon_path.to_string_lossy();
@@ -135,20 +129,14 @@ fn run() -> Result<(), ContextualError> {
" Invoke with -h|--help to see options or invoke as `miniserve .` to hide this advice."
);
print!("Starting server in ");
- io::stdout().flush().map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to write data".to_string(),
- e,
- ))
- })?;
+ io::stdout()
+ .flush()
+ .map_err(|e| ContextualError::IOError("Failed to write data".to_string(), e))?;
for c in "3… 2… 1… \n".chars() {
print!("{}", c);
- io::stdout().flush().map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to write data".to_string(),
- e,
- ))
- })?;
+ io::stdout()
+ .flush()
+ .map_err(|e| ContextualError::IOError("Failed to write data".to_string(), e))?;
thread::sleep(Duration::from_millis(500));
}
}
@@ -196,10 +184,10 @@ fn run() -> Result<(), ContextualError> {
// Note that this should never fail, since CLI parsing succeeded
// This means the format of each IP address is valid, and so is the port
// Valid IpAddr + valid port == valid SocketAddr
- return Err(ContextualError::new(ContextualErrorKind::ParseError(
+ return Err(ContextualError::ParseError(
"string as socket address".to_string(),
e.to_string(),
- )));
+ ));
}
};
@@ -210,12 +198,7 @@ fn run() -> Result<(), ContextualError> {
.configure(configure_app)
})
.bind(socket_addresses.as_slice())
- .map_err(|e| {
- ContextualError::new(ContextualErrorKind::IOError(
- "Failed to bind server".to_string(),
- e,
- ))
- })?
+ .map_err(|e| ContextualError::IOError("Failed to bind server".to_string(), e))?
.shutdown_timeout(0)
.start();