Repository: static-web-server/static-web-server (language: rust)

Issue:
static compressed index.html is missed when accessing a directory
**Describe the bug**
The static compressed index.html is missed when accessing a directory.

**To Reproduce**
* create a `doc` directory with an `index.html` file in it
* generate the `index.html.gz` file in the `doc` directory (`gzip -k index.html`) 
* activate the static compression feature
* (optionally) disable the dynamic compression feature
* activate the tracing logs
* run the sws server
* run a GET request on the directory (`xh localhost/doc/`)
* see in the log that SWS tries to access `doc.gz`
* if the dynamic compression was disable, see that the file is serve uncompressed

Note that it uses the statically compressed file when explicitly providing `index.html` in the url (`xh localhost/doc/index.html`).

**Expected behavior**
sws should be able to serve the statically compressed index.html.gz when serving a directory.

**Logs/Screenshots**

```
2023-02-28T06:46:56.326898Z  INFO static_web_server::handler: incoming request: method=GET uri=/doc/
2023-02-28T06:46:56.326912Z TRACE static_web_server::static_files: dir: base="/public", route="doc/"
2023-02-28T06:46:56.326928Z TRACE static_web_server::compression_static: preparing pre-compressed file path variant of /public/doc
2023-02-28T06:46:56.326947Z TRACE static_web_server::compression_static: getting metadata for pre-compressed file variant /public/doc.gz
2023-02-28T06:46:56.326984Z DEBUG static_web_server::static_files: file not found: "/public/doc.gz" Os { code: 2, kind: NotFound, message: "No such file or directory" }
2023-02-28T06:46:56.327003Z TRACE static_web_server::static_files: getting metadata for file /public/doc
2023-02-28T06:46:56.327018Z TRACE static_web_server::static_files: file found: "/public/doc"
2023-02-28T06:46:56.327029Z DEBUG static_web_server::static_files: dir: appending an index.html to the directory path
2023-02-28T06:46:56.327048Z TRACE static_web_server::static_files: file found: "/public/doc/index.html"
```

**Environment and Specs**
 - static-web-server: 2.14.2
 - OS: k8s on linux
 - Client: xh 0.16.1, chrome 110.0.5481.77

static compressed index.html is missed when accessing a directory
**Describe the bug**
The static compressed index.html is missed when accessing a directory.

**To Reproduce**
* create a `doc` directory with an `index.html` file in it
* generate the `index.html.gz` file in the `doc` directory (`gzip -k index.html`) 
* activate the static compression feature
* (optionally) disable the dynamic compression feature
* activate the tracing logs
* run the sws server
* run a GET request on the directory (`xh localhost/doc/`)
* see in the log that SWS tries to access `doc.gz`
* if the dynamic compression was disable, see that the file is serve uncompressed

Note that it uses the statically compressed file when explicitly providing `index.html` in the url (`xh localhost/doc/index.html`).

**Expected behavior**
sws should be able to serve the statically compressed index.html.gz when serving a directory.

**Logs/Screenshots**

```
2023-02-28T06:46:56.326898Z  INFO static_web_server::handler: incoming request: method=GET uri=/doc/
2023-02-28T06:46:56.326912Z TRACE static_web_server::static_files: dir: base="/public", route="doc/"
2023-02-28T06:46:56.326928Z TRACE static_web_server::compression_static: preparing pre-compressed file path variant of /public/doc
2023-02-28T06:46:56.326947Z TRACE static_web_server::compression_static: getting metadata for pre-compressed file variant /public/doc.gz
2023-02-28T06:46:56.326984Z DEBUG static_web_server::static_files: file not found: "/public/doc.gz" Os { code: 2, kind: NotFound, message: "No such file or directory" }
2023-02-28T06:46:56.327003Z TRACE static_web_server::static_files: getting metadata for file /public/doc
2023-02-28T06:46:56.327018Z TRACE static_web_server::static_files: file found: "/public/doc"
2023-02-28T06:46:56.327029Z DEBUG static_web_server::static_files: dir: appending an index.html to the directory path
2023-02-28T06:46:56.327048Z TRACE static_web_server::static_files: file found: "/public/doc/index.html"
```

**Environment and Specs**
 - static-web-server: 2.14.2
 - OS: k8s on linux
 - Client: xh 0.16.1, chrome 110.0.5481.77



Discussion / hints:
Can you please share also how are you calling SWS like options used or config settings?
sure, it's run with `static-web-server --config-file /sws.toml` and `sws.toml` is 

```toml
[general]
root = "/public"
log-level = "trace"
# we want to serve the pre-compressed files, but don't want to compress them on the fly
compression = false
compression-static = true
```
I just checked this and effectively, SWS is not appending an `index.html` for directories therefore the issue.
A bugfix should come in next hours.
Can you please share also how are you calling SWS like options used or config settings?
sure, it's run with `static-web-server --config-file /sws.toml` and `sws.toml` is 

```toml
[general]
root = "/public"
log-level = "trace"
# we want to serve the pre-compressed files, but don't want to compress them on the fly
compression = false
compression-static = true
```
I just checked this and effectively, SWS is not appending an `index.html` for directories therefore the issue.
A bugfix should come in next hours.

Fix patch:
diff --git a/src/compression_static.rs b/src/compression_static.rs
index f7762499..3b113101 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 7c915fb5..1096bc5f 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) => {


Test patch: