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

Issue:
Incorrect `content-encoding` for `gzip` when file is already available + `compression-static`
### Search for duplicate issues

- [X] I already searched, and this issue is not a duplicate.

### Issue scope

Docker / Kubernetes

### Describe the bug

If I run `SWS` with my "frontend" package, with both regular and pre-compressed files (`.gzip`), I see an unexpected `content-encoding` returned by `SWS`: `content-encoding: gzip, gzip`.

After verification, the content is packaged twice, aka a `gzip` inside a `gzip`.

This generates issues with Apple based browsers, because they don't process `gzip` twice and so can't parse `js` or `css` after the first "unpackaging".



### How to reproduce it

Find attached files I have generated, with the unexpected result in `SWS`: 

[app-css.zip](https://github.com/user-attachments/files/16589058/app-css.zip)

If I run the `SWS` with `docker run -it --rm -p 8080:8080 ui-for-testing`, using the following configuration: 

```toml
[general]

host = "::"
port = 8080
log-level = "info"

cache-control-headers = true
compression = true
compression-static = true
security-headers = true
directory-listing = false
redirect-trailing-slash = true
ignore-hidden-files = true
```

I get the following result when I run the following `curl` call: 

```sh
curl 'http://localhost:8080/app.min.css' \
      -H 'Accept: */*' \
      -H 'Accept-Encoding: gzip' \
      -v -o nul &| grep content-encoding
< content-encoding: gzip, gzip
```

If I set `compression-static = false`, the result is "normal", but I suspect the compression is done by `SWS` and doesn't leverage the pre-built `gzip` file.

```
curl 'http://localhost:8080/app.min.css' \
      -H 'Accept: */*' \
      -H 'Accept-Encoding: gzip' \
      -v -o nul &| grep content-encoding
< content-encoding: gzip
```

### Expected behavior

I expect the system to leverage the pre-build `gzip` and returns a `content-type` with only `gzip` once. 



### Complementary information

From the investigation I did, this bug has been introduced after `2.31.0`. 

If I change my `Dockerfile` to `2.32.0`, I have the issue, but I don't have it with `2.31.0`, of course with the same config and files. 



### Build target

Docker linux/amd64

### Environment and specs

- [x] **static-web-server:** [e.g. v2.32.0+]
- [ ] **Rust:** [e.g. v1.78.0]
- [x] **OS:** Distrolesss
- [x] **Arch:** x86_64 (64-bit), ARM (32-bit), ARM64 (64-bit)
- [x] **Docker:** 27.1.1
- [x] **Client:** All (Safari, Chrome, Arc, `curl`)


### Additional context

This issue has been found while developing on my application, [Podcast-Server](https://gitlab.com/davinkevin/Podcast-Server/), and you can find the code used by the UI [here](https://gitlab.com/davinkevin/Podcast-Server/-/tree/main/ui/src/docker?ref_type=heads)

Pull request:
Fix wrong `Content-Encoding` when enabling both compression and compression-static features

<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes but try to be as concise as possible -->

This PR fixes a wrong `Content-Encoding` header value in the response when `compression` and `compression-static` features are enabled due to SWS compression (dynamic) module performing the post-processing even if a pre-compressed file was found. 

## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

It fixes #470

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment and the tests you ran to -->
<!--- See how your change affects other areas of the code, etc. -->

**Before**

```sh
curl -sD - -o /dev/null -H "Accept-Encoding: gzip, zstd, br" http://localhost:8787/assets/main.css
# HTTP/1.1 200 OK
# last-modified: Mon, 12 Aug 2024 22:56:47 GMT
# content-type: text/css
# accept-ranges: bytes
# vary: accept-encoding
# content-encoding: gzip, gzip
# cache-control: public, max-age=31536000
# transfer-encoding: chunked
# date: Mon, 12 Aug 2024 23:16:59 GMT
```

**After**

```sh
curl -sD - -o /dev/null -H "Accept-Encoding: gzip, zstd, br" http://localhost:8787/assets/main.css
# HTTP/1.1 200 OK
# last-modified: Mon, 12 Aug 2024 22:56:47 GMT
# content-type: text/css
# accept-ranges: bytes
# content-encoding: gzip
# vary: accept-encoding
# cache-control: public, max-age=31536000
# transfer-encoding: chunked
# date: Mon, 12 Aug 2024 23:18:14 GMT
```

## Screenshots (if appropriate):


Patch:
diff --git a/src/compression.rs b/src/compression.rs
index 6914778..babfe44 100644
--- a/src/compression.rs
+++ b/src/compression.rs
@@ -98,6 +98,11 @@ pub(crate) fn post_process<T>(
         return Ok(resp);
     }
 
+    let is_precompressed = resp.headers().get(CONTENT_ENCODING).is_some();
+    if is_precompressed {
+        return Ok(resp);
+    }
+
     // Compression content encoding varies so use a `Vary` header
     resp.headers_mut().insert(
         hyper::header::VARY,


Test patch:
diff --git a/tests/compression.rs b/tests/compression.rs
index ebd80d9..8c8e7e4 100644
--- a/tests/compression.rs
+++ b/tests/compression.rs
@@ -16,7 +16,7 @@ pub mod tests {
 
     #[tokio::test]
     async fn compression_file() {
-        let opts = fixture_settings("toml/handler.toml");
+        let opts = fixture_settings("toml/handler_fixtures.toml");
         let general = General {
             compression: true,
             compression_static: true,
diff --git a/tests/fixtures/toml/handler_fixtures.toml b/tests/fixtures/toml/handler_fixtures.toml
new file mode 100644
index 0000000..3a002af
--- /dev/null
+++ b/tests/fixtures/toml/handler_fixtures.toml
@@ -0,0 +1,9 @@
+[general]
+
+root = "tests/fixtures/public"
+
+[advanced]
+
+[[advanced.headers]]
+source = "**/*.{html,htm}"
+headers = { Server = "Static Web Server" }