diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | Cargo.lock | 105 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | src/file_op.rs | 45 | ||||
-rw-r--r-- | tests/upload_files.rs | 4 |
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) @@ -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", @@ -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] @@ -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, |