index : static-web-server.git

ascending towards madness

author Jose Quintana <1700322+joseluisq@users.noreply.github.com> 2023-03-05 22:33:19.0 +00:00:00
committer GitHub <noreply@github.com> 2023-03-05 22:33:19.0 +00:00:00
commit
06cba46c5545ce2b5271570320e0e22702bc66b1 [patch]
tree
c706b4681d601f8e9e6b860299ed00fb8eb82e14
parent
db063e45ab8ae4bb3a9178b06b2ac103087dae55
download
06cba46c5545ce2b5271570320e0e22702bc66b1.tar.gz

fix: compression static auto index.html check missing (#186)

it also prevents trying to serve a pre-compressed file variant if the file found
was a directory (a folder named as a file)

fixes #178

Diff

 src/compression_static.rs |  9 +++++-
 src/static_files.rs       | 67 ++++++++++++++++++++++++++++++------------------
 2 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/src/compression_static.rs b/src/compression_static.rs
index f776249..3b11310 100644
--- a/src/compression_static.rs
+++ b/src/compression_static.rs
@@ -44,7 +44,14 @@ pub async fn precompressed_variant<'a>(
                filepath_precomp.display()
            );

            if let Ok((meta, _)) = file_metadata(&filepath_precomp) {
            if let Ok((meta, is_dir)) = file_metadata(&filepath_precomp) {
                if is_dir {
                    tracing::trace!(
                        "pre-compressed file variant found but it's a directory, skipping"
                    );
                    return None;
                }

                tracing::trace!("pre-compressed file variant found, serving it directly");

                let encoding = if ext == "gz" { "gzip" } else { ext };
diff --git a/src/static_files.rs b/src/static_files.rs
index 7c915fb..1096bc5 100644
--- a/src/static_files.rs
+++ b/src/static_files.rs
@@ -167,17 +167,6 @@ async fn composed_file_metadata<'a>(
    headers: &'a HeaderMap<HeaderValue>,
    compression_static: bool,
) -> Result<(&'a PathBuf, Metadata, bool, Option<(PathBuf, &'a str)>), StatusCode> {
    // First pre-compressed variant check for the given file path
    let mut tried_precompressed = false;
    if compression_static {
        tried_precompressed = true;
        if let Some((path, meta, ext)) =
            compression_static::precompressed_variant(file_path, headers).await
        {
            return Ok((file_path, meta, false, Some((path, ext))));
        }
    }

    tracing::trace!("getting metadata for file {}", file_path.display());

    match file_metadata(file_path.as_ref()) {
@@ -187,7 +176,17 @@ async fn composed_file_metadata<'a>(
                tracing::debug!("dir: appending an index.html to the directory path");
                file_path.push("index.html");

                // If file exists then overwrite the `meta`
                // Pre-compressed variant check for the autoindex
                if compression_static {
                    if let Some((path, meta, ext)) =
                        compression_static::precompressed_variant(file_path, headers).await
                    {
                        return Ok((file_path, meta, false, Some((path, ext))));
                    }
                }

                // Otherwise, just fallback to finding the index.html
                // and overwrite the current `meta`
                // Also noting that it's still a directory request
                if let Ok(meta_res) = file_metadata(file_path.as_ref()) {
                    (meta, _) = meta_res
@@ -203,23 +202,22 @@ async fn composed_file_metadata<'a>(
                        file_path.push("index.html");
                    }
                }
            } else {
                // Fallback pre-compressed variant check for the specific file
                if compression_static {
                    if let Some((path, meta, ext)) =
                        compression_static::precompressed_variant(file_path, headers).await
                    {
                        return Ok((file_path, meta, false, Some((path, ext))));
                    }
                }
            }

            Ok((file_path, meta, is_dir, None))
        }
        Err(err) => {
            if err == StatusCode::NOT_FOUND {
                // If the file path doesn't exist, we try to find the path suffixed with `.html`.
                // For example: `/posts/article` will fallback to `/posts/article.html`
                let new_meta: Option<Metadata>;
                (file_path, new_meta) = prefix_file_html_metadata(file_path);
                if let Some(new_meta) = new_meta {
                    return Ok((file_path, new_meta, false, None));
                }
            }

            // Second pre-compressed variant check for the given file path
            if compression_static && !tried_precompressed {
            // Pre-compressed variant check for the file not found
            if compression_static {
                if let Some((path, meta, ext)) =
                    compression_static::precompressed_variant(file_path, headers).await
                {
@@ -227,12 +225,31 @@ async fn composed_file_metadata<'a>(
                }
            }

            // Otherwise, if the file path doesn't exist then
            // we try to find the path suffixed with `.html`.
            // For example: `/posts/article` will fallback to `/posts/article.html`
            let new_meta: Option<Metadata>;
            (file_path, new_meta) = prefix_file_html_metadata(file_path);
            match new_meta {
                Some(new_meta) => return Ok((file_path, new_meta, false, None)),
                _ => {
                    // Last pre-compressed variant check or the prefixed file not found
                    if compression_static {
                        if let Some((path, meta, ext)) =
                            compression_static::precompressed_variant(file_path, headers).await
                        {
                            return Ok((file_path, meta, false, Some((path, ext))));
                        }
                    }
                }
            }

            Err(err)
        }
    }
}

/// Try to find the file system metadata for the given file path.
/// Try to find the file system metadata for the given file path or returns an `Not Found` error.
pub fn file_metadata(file_path: &Path) -> Result<(Metadata, bool), StatusCode> {
    match std::fs::metadata(file_path) {
        Ok(meta) => {