Repository: traefik/traefik (language: go)

Issue:
Traefik v3-beta5 compress middleware overrides http response status code
### Welcome!

- [X] Yes, I've searched similar issues on [GitHub](https://github.com/traefik/traefik/issues) and didn't find any.
- [X] Yes, I've searched similar issues on the [Traefik community forum](https://community.traefik.io) and didn't find any.

### What did you do?

Hi all, 

currently, I have 2 environments with different traefik instances (same config, but different versions)
- DEV: Traefik v3-beta5
- PRO: Traefik 2.10.7

In both of them I have registered many routes, services and middlewares (same config for both environments of each route/service/middleware), but after the upgrade to v3-beta in the dev environment I saw a wrong behavior while using the compress middleware.

When I request to a PRO route expecting a status code different from 200, (400, 401,403...) all is fine.
When I request to a DEV route expecting a status code different from 200, (400, 401,403...) the returned status code is always 200.

### What did you see instead?


| ENV| COMPRESS ENABLED| EXPECTED STATUS CODE | RETURNED STATUS CODE | IMAGES |
|--------|--------|--------|--------|--------|
| DEV | FALSE | 400 | 400 | ![Image 001](https://github.com/traefik/traefik/assets/1176404/f482baa0-cdea-41d7-a77f-ec51ef3b66cb) ![Image 002](https://github.com/traefik/traefik/assets/1176404/6538e81d-cf02-4c55-a602-ad2387368642) |
| DEV | TRUE | 400 | 200 | ![Image 003](https://github.com/traefik/traefik/assets/1176404/1e5e1f04-0747-41b6-aeec-32a3e7592459) ![Image 004](https://github.com/traefik/traefik/assets/1176404/d81b2481-13de-47bc-9032-2fea6fb0a6f2) |


### What version of Traefik are you using?

Version:      3.0.0-beta5
Codename:     beaufort
Go version:   go1.21.4
Built:        2023-11-29T15:14:06Z
OS/Arch:      linux/amd64


### What is your environment & configuration?

```yaml
# (paste your configuration here)
```

Here is the route and service configuration:

![image](https://github.com/traefik/traefik/assets/1176404/f3d9cada-3079-4637-830e-dba747aa6b1a)

Just remove the middleware label to change the behavior.

The compress middleware is define as:

`traefik.http.middlewares.compress.compress=true`

in the traefik service.


### If applicable, please paste the log output in DEBUG level

_No response_


Discussion / hints:
Hello @rmartcas,

Thanks for reporting this!

It would be more handy if you can provide a fully reproducible case, like a docker-compose with both Traefik and the service, and an example command to make the request (e.g.: curl).

Also, can you please indicate if the service behind Traefik is using 1xxs informational responses, and if it does compress responses as well?
Hi!, after some digging i have new conclusions:

I have a property on my spring boot service that enables o disables the compression acording to the official doc:

server.compression.enabled = true|false

The next table shows the tests with different settings:

| Traefik compress middleware enabled | Spring boot compress enabled | Expected status code | Returned status code | IMAGES |
|---|---|---|---|---|
| YES | NO | 400 | 400 |  |
| **YES** | **YES** | **400** | **200** |  |
| NO | YES | 400 | 400 |  |
| NO | NO | 400 | 400 |  |

So, when the service has the compression enabled and traefik has the compression middleware enabled too the response status is changed from 400 to 200.
Hi! @rtribotte , here you have a repo with the full demo:

https://github.com/rmartcas/traefik3-demo

Just compile the project with "mvn clean install", then run the docker compose with "docker-compose up".

Then you can access the urls described in the readme to check the response headers and status.

Regards
Is there any progress on this? @rtribotte 

Regards
Hello @rmartcas,

Sorry for the late answer, thanks for your feedback.
I'm going to look into it and let you know.
Hello @rmartcas,

I have tried your setup without being able to reproduce the issue (I used specifically the v3.0.0-beta5 image).
I have used the following curl commands:
- `curl -v http://demo4.localhost/demo/ko`
- `curl -v http://demo4.localhost/demo/ko -H "Accept-Encoding: gzip"`
- `curl -v http://demo4.localhost/demo/ko -H "Accept-Encoding: br"`

Can you please provide more insights about how the request should be made to reproduce the problem?

As a side note, this seems unrelated to the matter here, but the compress middleware behavior has changed recently in this PR: https://github.com/traefik/traefik/pull/10178.
This is yet unreleased though.
Hi @rtribotte , try with this command:

`curl -v -H "Accept-Encoding: gzip, deflate, br" -H Host:demo4.localhost http://127.0.0.1/demo/ko`

Is the same as the browsers sends.

The output from this command:

![image](https://github.com/traefik/traefik/assets/1176404/d940e3e9-c288-4cec-a88e-19336ee4833b)


Regards

Fix patch:
diff --git a/pkg/middlewares/compress/brotli/brotli.go b/pkg/middlewares/compress/brotli/brotli.go
index c95a5ff664..142eb78ee7 100644
--- a/pkg/middlewares/compress/brotli/brotli.go
+++ b/pkg/middlewares/compress/brotli/brotli.go
@@ -138,6 +138,7 @@ func (r *responseWriter) Write(p []byte) (int, error) {
 	// If we detect a contentEncoding, we know we are never going to compress.
 	if r.rw.Header().Get(contentEncoding) != "" {
 		r.compressionDisabled = true
+		r.rw.WriteHeader(r.statusCode)
 		return r.rw.Write(p)
 	}
 


Test patch:
diff --git a/pkg/middlewares/compress/brotli/brotli_test.go b/pkg/middlewares/compress/brotli/brotli_test.go
index 5e1bfeea70..445268f85f 100644
--- a/pkg/middlewares/compress/brotli/brotli_test.go
+++ b/pkg/middlewares/compress/brotli/brotli_test.go
@@ -27,7 +27,7 @@ func Test_Vary(t *testing.T) {
 	rw := httptest.NewRecorder()
 	h.ServeHTTP(rw, req)
 
-	assert.Equal(t, http.StatusOK, rw.Code)
+	assert.Equal(t, http.StatusAccepted, rw.Code)
 	assert.Equal(t, acceptEncoding, rw.Header().Get(vary))
 }
 
@@ -41,7 +41,7 @@ func Test_SmallBodyNoCompression(t *testing.T) {
 	h.ServeHTTP(rw, req)
 
 	// With less than 1024 bytes the response should not be compressed.
-	assert.Equal(t, http.StatusOK, rw.Code)
+	assert.Equal(t, http.StatusAccepted, rw.Code)
 	assert.Empty(t, rw.Header().Get(contentEncoding))
 	assert.Equal(t, smallTestBody, rw.Body.Bytes())
 }
@@ -55,6 +55,7 @@ func Test_AlreadyCompressed(t *testing.T) {
 	rw := httptest.NewRecorder()
 	h.ServeHTTP(rw, req)
 
+	assert.Equal(t, http.StatusAccepted, rw.Code)
 	assert.Equal(t, bigTestBody, rw.Body.Bytes())
 }
 
@@ -749,6 +750,7 @@ func newTestHandler(t *testing.T, body []byte) http.Handler {
 				rw.Header().Set("Content-Encoding", "br")
 			}
 
+			rw.WriteHeader(http.StatusAccepted)
 			_, err := rw.Write(body)
 			require.NoError(t, err)
 		}),