Add --directory-size flag to enable directory size calculation

This is turned off by default as it's potentially quite IO intensive, especially on HDDs.
This commit is contained in:
Sven-Hendrik Haase 2025-03-20 13:48:26 +01:00
parent 7edaaf7647
commit 900c0035b3
No known key found for this signature in database
GPG Key ID: 39E4B877E62EB915
5 changed files with 38 additions and 20 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add well-known healthcheck route at `/__miniserve_internal/healthcheck` (of `/<prefix>/__miniserve_internal/healthcheck` when using `--route-prefix`)
- Add asynchronous recursive directory size counting [#1482](https://github.com/svenstaro/miniserve/pull/1482)
- Add link to miniserve GitHub page to footer
- Add `--directory-size` flag to enable directory size counting
## [0.29.0] - 2025-02-06
- Make URL encoding fully WHATWG-compliant [#1454](https://github.com/svenstaro/miniserve/pull/1454) (thanks @cyqsimon)

View File

@ -217,6 +217,12 @@ pub struct CliArgs {
)]
pub web_upload_concurrency: usize,
/// Enable recursive directory size calculation
///
/// This is disabled by default because it is a potentially fairly IO intensive operation.
#[arg(long = "directory-size", env = "MINISERVE_DIRECTORY_SIZE")]
pub directory_size: bool,
/// Enable creating directories
#[arg(
short = 'U',

View File

@ -104,6 +104,9 @@ pub struct MiniserveConfig {
/// Enable QR code display
pub show_qrcode: bool,
/// Enable recursive directory size calculation
pub directory_size: bool,
/// Enable creating directories
pub mkdir_enabled: bool,
@ -320,6 +323,7 @@ impl MiniserveConfig {
pretty_urls: args.pretty_urls,
overwrite_files: args.overwrite_files,
show_qrcode: args.qrcode,
directory_size: args.directory_size,
mkdir_enabled: args.mkdir_enabled,
file_upload: args.allowed_upload_dir.is_some(),
web_upload_concurrency: args.web_upload_concurrency,

View File

@ -457,28 +457,32 @@ async fn api(
) -> Result<impl Responder, RuntimeError> {
match command.into_inner() {
ApiCommand::DirSize(path) => {
// The dir argument might be percent-encoded so let's decode it just in case.
let decoded_path = percent_decode_str(&path)
.decode_utf8()
.map_err(|e| RuntimeError::ParseError(path.clone(), e.to_string()))?;
if config.directory_size {
// The dir argument might be percent-encoded so let's decode it just in case.
let decoded_path = percent_decode_str(&path)
.decode_utf8()
.map_err(|e| RuntimeError::ParseError(path.clone(), e.to_string()))?;
// Convert the relative dir to an absolute path on the system.
let sanitized_path = file_utils::sanitize_path(&*decoded_path, true)
.expect("Expected a path to directory");
// Convert the relative dir to an absolute path on the system.
let sanitized_path = file_utils::sanitize_path(&*decoded_path, true)
.expect("Expected a path to directory");
let full_path = config
.path
.canonicalize()
.expect("Couldn't canonicalize path")
.join(sanitized_path);
info!("Requested directory listing for {full_path:?}");
let full_path = config
.path
.canonicalize()
.expect("Couldn't canonicalize path")
.join(sanitized_path);
info!("Requested directory listing for {full_path:?}");
let dir_size = recursive_dir_size(&full_path).await?;
if config.show_exact_bytes {
Ok(format!("{dir_size} B"))
let dir_size = recursive_dir_size(&full_path).await?;
if config.show_exact_bytes {
Ok(format!("{dir_size} B"))
} else {
let dir_size = ByteSize::b(dir_size);
Ok(dir_size.to_string())
}
} else {
let dir_size = ByteSize::b(dir_size);
Ok(dir_size.to_string())
Ok("-".to_string())
}
}
}

View File

@ -16,7 +16,10 @@ use crate::fixtures::{DIRECTORIES, Error, TestServer, server};
#[case(utf8_percent_encode(DIRECTORIES[0], NON_ALPHANUMERIC).to_string())]
#[case(utf8_percent_encode(DIRECTORIES[1], NON_ALPHANUMERIC).to_string())]
#[case(utf8_percent_encode(DIRECTORIES[2], NON_ALPHANUMERIC).to_string())]
fn api_dir_size(#[case] dir: String, server: TestServer) -> Result<(), Error> {
fn api_dir_size(
#[case] dir: String,
#[with(&["--directory-size"])] server: TestServer,
) -> Result<(), Error> {
let mut command = HashMap::new();
command.insert("DirSize", dir);
@ -44,7 +47,7 @@ fn api_dir_size(#[case] dir: String, server: TestServer) -> Result<(), Error> {
#[case(r"C:\foo")]
#[case(r"\foo")]
fn api_dir_size_prevent_path_transversal_attacks(
server: TestServer,
#[with(&["--directory-size"])] server: TestServer,
#[case] path: &str,
) -> Result<(), Error> {
let mut command = HashMap::new();