aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock105
-rw-r--r--Cargo.toml3
-rw-r--r--README.md4
-rw-r--r--src/file_op.rs45
-rw-r--r--tests/upload_files.rs4
6 files changed, 87 insertions, 76 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef7f8bd..0e25460 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header -->
## [Unreleased] - ReleaseDate
+- Properly handle read-only errors on Windows [#1310](https://github.com/svenstaro/miniserve/pull/1310) (thanks @ViRb3)
+- Use `tokio::fs` instead of `std::fs` to enable async file operations [#445](https://github.com/svenstaro/miniserve/issues/445)
## [0.25.0] - 2024-01-07
- Add `--pretty-urls` [#1193](https://github.com/svenstaro/miniserve/pull/1193) (thanks @nlopes)
diff --git a/Cargo.lock b/Cargo.lock
index ee63513..8e7371a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,9 +21,9 @@ dependencies = [
[[package]]
name = "actix-files"
-version = "0.6.4"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc517050e349356239da19a5e100cd61c21658b3ae183b02c1c6799c581bddf3"
+checksum = "bf0bdd6ff79de7c9a021f5d9ea79ce23e108d8bfc9b49b5b4a2cf6fad5a35212"
dependencies = [
"actix-http",
"actix-service",
@@ -371,9 +371,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.5"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
+checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -425,9 +425,9 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]]
name = "assert_cmd"
-version = "2.0.12"
+version = "2.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
+checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467"
dependencies = [
"anstyle",
"bstr",
@@ -440,9 +440,9 @@ dependencies = [
[[package]]
name = "assert_fs"
-version = "1.1.0"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adc5d78e9048d836d12a0c0040ca5f45b18a94d204b4ba4f677a8a7de162426b"
+checksum = "2cd762e110c8ed629b11b6cde59458cc1c71de78ebbcc30099fc8e0403a2a2ec"
dependencies = [
"anstyle",
"doc-comment",
@@ -476,9 +476,9 @@ dependencies = [
[[package]]
name = "base64"
-version = "0.21.5"
+version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bit-set"
@@ -622,9 +622,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.4.13"
+version = "4.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
+checksum = "58e54881c004cec7895b0068a0a954cd5d62da01aef83fa35b1e594497bf5445"
dependencies = [
"clap_builder",
"clap_derive",
@@ -632,9 +632,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.4.12"
+version = "4.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
+checksum = "59cb82d7f531603d2fd1f507441cdd35184fa81beff7bd489570de7f773460bb"
dependencies = [
"anstream",
"anstyle",
@@ -672,9 +672,9 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "clap_mangen"
-version = "0.2.16"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10b5db60b3310cdb376fbeb8826e875a38080d0c61bdec0a91a3da8338948736"
+checksum = "4a7c2b01e5e779c19f46a94bbd398f33ae63b0f78c07108351fb4536845bb7fd"
dependencies = [
"clap",
"roff",
@@ -769,34 +769,28 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
-version = "0.8.4"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
- "cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
-version = "0.9.17"
+version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
- "autocfg",
- "cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
-version = "0.8.18"
+version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
-dependencies = [
- "cfg-if",
-]
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "crypto-common"
@@ -1189,9 +1183,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.11"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
@@ -1225,11 +1219,11 @@ dependencies = [
[[package]]
name = "globwalk"
-version = "0.8.1"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
+checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.1",
"ignore",
"walkdir",
]
@@ -1261,9 +1255,9 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.3.22"
+version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
+checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7"
dependencies = [
"bytes",
"fnv",
@@ -1552,9 +1546,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.66"
+version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
+checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
dependencies = [
"wasm-bindgen",
]
@@ -1582,9 +1576,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.151"
+version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]]
name = "libflate"
@@ -1775,6 +1769,7 @@ dependencies = [
"strum",
"tar",
"thiserror",
+ "tokio",
"url",
"zip",
]
@@ -2292,9 +2287,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.38.28"
+version = "0.38.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
+checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
dependencies = [
"bitflags 2.4.1",
"errno",
@@ -2986,9 +2981,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.89"
+version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
+checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -2996,9 +2991,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.89"
+version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
+checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
dependencies = [
"bumpalo",
"log",
@@ -3011,9 +3006,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.39"
+version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
+checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461"
dependencies = [
"cfg-if",
"js-sys",
@@ -3023,9 +3018,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.89"
+version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
+checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -3033,9 +3028,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.89"
+version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
+checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
dependencies = [
"proc-macro2",
"quote",
@@ -3046,15 +3041,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.89"
+version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
+checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
[[package]]
name = "web-sys"
-version = "0.3.66"
+version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
+checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
dependencies = [
"js-sys",
"wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index 6284689..b5e65e3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ panic = 'abort'
strip = true
[dependencies]
-actix-files = "0.6.4"
+actix-files = "0.6.5"
actix-multipart = "0.6"
actix-web = { version = "4", features = ["macros", "compress-brotli", "compress-gzip", "compress-zstd"], default-features = false }
actix-web-httpauth = "0.8"
@@ -57,6 +57,7 @@ socket2 = "0.5"
strum = { version = "0.25", features = ["derive"] }
tar = "0.4"
thiserror = "1"
+tokio = { version = "1.35.1", features = ["fs"] }
zip = { version = "0.6.5", default-features = false }
[features]
diff --git a/README.md b/README.md
index 13eadcc..b3c832a 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ Sometimes this is just a more practical and quick way than doing things properly
pw=$(echo -n "123" | sha256sum | cut -f 1 -d ' ')
miniserve --auth joe:sha256:$pw unreleased-linux-distros/
-
+
### Require username/password from file (separate logins with new lines):
miniserve --auth-file auth.txt unreleased-linux-distros/
@@ -398,6 +398,8 @@ Alternatively install with [Scoop](https://scoop.sh/):
podman run -v /tmp:/tmp -p 8080:8080 --rm -it docker.io/svenstaro/miniserve /tmp
+**With Helm:** See [this third-party Helm chart](https://codeberg.org/wrenix/helm-charts/src/branch/main/miniserve) by @wrenix.
+
## Shell completions
If you'd like to make use of the built-in shell completion support, you need to run `miniserve
diff --git a/src/file_op.rs b/src/file_op.rs
index 590ab25..760b23e 100644
--- a/src/file_op.rs
+++ b/src/file_op.rs
@@ -1,13 +1,14 @@
//! Handlers for file upload and removal
-use std::{
- io::Write,
- path::{Component, Path, PathBuf},
-};
+use std::io::ErrorKind;
+use std::path::{Component, Path, PathBuf};
use actix_web::{http::header, web, HttpRequest, HttpResponse};
+use futures::TryFutureExt;
use futures::TryStreamExt;
use serde::Deserialize;
+use tokio::fs::File;
+use tokio::io::AsyncWriteExt;
use crate::{
config::MiniserveConfig, errors::ContextualError, file_utils::contains_symlink,
@@ -27,15 +28,23 @@ async fn save_file(
return Err(ContextualError::DuplicateFileError);
}
- let file = std::fs::File::create(&file_path).map_err(|e| {
- ContextualError::IoError(format!("Failed to create {}", file_path.display()), e)
- })?;
+ let file = match File::create(&file_path).await {
+ Err(err) if err.kind() == ErrorKind::PermissionDenied => Err(
+ ContextualError::InsufficientPermissionsError(file_path.display().to_string()),
+ ),
+ Err(err) => Err(ContextualError::IoError(
+ format!("Failed to create {}", file_path.display()),
+ err,
+ )),
+ Ok(v) => Ok(v),
+ }?;
let (_, written_len) = field
.map_err(|x| ContextualError::MultipartError(x.to_string()))
.try_fold((file, 0u64), |(mut file, written_len), bytes| async move {
file.write_all(bytes.as_ref())
- .map_err(|e| ContextualError::IoError("Failed to write to file".to_string(), e))?;
+ .map_err(|e| ContextualError::IoError("Failed to write to file".to_string(), e))
+ .await?;
Ok((file, written_len + bytes.len() as u64))
})
.await?;
@@ -54,7 +63,7 @@ async fn handle_multipart(
) -> Result<u64, ContextualError> {
let field_name = field.name().to_string();
- match std::fs::metadata(&path) {
+ match tokio::fs::metadata(&path).await {
Err(_) => Err(ContextualError::InsufficientPermissionsError(
path.display().to_string(),
)),
@@ -62,9 +71,6 @@ async fn handle_multipart(
"cannot upload file to {}, since it's not a directory",
&path.display()
))),
- Ok(metadata) if metadata.permissions().readonly() => Err(
- ContextualError::InsufficientPermissionsError(path.display().to_string()),
- ),
Ok(_) => Ok(()),
}?;
@@ -127,11 +133,16 @@ async fn handle_multipart(
}
}
- std::fs::create_dir_all(&absolute_path).map_err(|e| {
- ContextualError::IoError(format!("Failed to create {}", user_given_path.display()), e)
- })?;
-
- return Ok(0);
+ return match tokio::fs::create_dir_all(&absolute_path).await {
+ Err(err) if err.kind() == ErrorKind::PermissionDenied => Err(
+ ContextualError::InsufficientPermissionsError(path.display().to_string()),
+ ),
+ Err(err) => Err(ContextualError::IoError(
+ format!("Failed to create {}", user_given_path.display()),
+ err,
+ )),
+ Ok(_) => Ok(0),
+ };
}
let filename = field.content_disposition().get_filename().ok_or_else(|| {
diff --git a/tests/upload_files.rs b/tests/upload_files.rs
index 8cb3e8e..77a9dc3 100644
--- a/tests/upload_files.rs
+++ b/tests/upload_files.rs
@@ -122,8 +122,8 @@ fn uploading_files_is_restricted(#[case] server: TestServer) -> Result<(), Error
#[case(server(&["-u", "./-someDir"]), vec!["./-someDir"])]
#[case(server(&["-u", Path::new("someDir/some_sub_dir").to_str().unwrap()]),
vec!["someDir/some_sub_dir"])]
-#[case(server(&["-u", Path::new("someDir/some_sub_dir").to_str().unwrap(),
- "-u", Path::new("someDir/some_other_dir").to_str().unwrap()]),
+#[case(server(&["-u", Path::new("someDir/some_sub_dir").to_str().unwrap(),
+ "-u", Path::new("someDir/some_other_dir").to_str().unwrap()]),
vec!["someDir/some_sub_dir", "someDir/some_other_dir"])]
fn uploading_files_to_allowed_dir_works(
#[case] server: TestServer,