Repository: traefik/traefik (language: go)

Issue:
errors middleware trigged on 404, forwards request and offers download instead
### 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?

I've 2 services

* `app1` is a normal web page
* `app2` is only responsible for serving error messages
* `app1` has a errors middleware configured that looks for 404 error and then uses `app2` to display error content
* the error page of `app2` should be visible and have a status 404

### What did you see instead?

The brower offers a download which is a gzipped version of the correct error page

It seems like neither the correct status code nor the correct headers are transported back to the client, so the browser tries to download it as a file.

### What version of Traefik are you using?

Version:      2.8.1
Codename:     vacherin
Go version:   go1.17.11
Built:        2022-07-11T14:06:57Z
OS/Arch:      linux/arm64


### What is your environment & configuration?

```yaml
version: "3.7"
services:
  app1:
    build: .
    environment:
      NAME: app1
    ports:
      - "3000:3000"
    labels:
      - "traefik.enable=true"

      - "traefik.http.middlewares.http-errors.errors.status=404"
      - "traefik.http.middlewares.http-errors.errors.service=app2"
      - "traefik.http.middlewares.http-errors.errors.query=/test"

      - "traefik.http.routers.app1.rule=HostRegexp(`{host:.*}`)"
      - "traefik.http.routers.app1.entrypoints=web"
      - "traefik.http.routers.app1.middlewares=http-errors"
  app2:
    build: .
    environment:
      NAME: app2
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.app2.loadbalancer.server.port=3000"
  traefik:
    image: traefik:latest
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--log.level=DEBUG"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
```

Reproduction can be found here: https://github.com/Torsten85/traefik-errors


### If applicable, please paste the log output in DEBUG level

```
my-app-traefik-1  | time="2022-08-04T18:34:40Z" level=debug msg="vulcand/oxy/roundrobin/rr: begin ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/x\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/1.1\",\"ProtoMajor\":1,\"ProtoMinor\":1,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"de,en-US;q=0.9,en;q=0.8\"],\"Connection\":[\"keep-alive\"],\"Sec-Ch-Ua\":[\"\\\".Not/A)Brand\\\";v=\\\"99\\\", \\\"Google Chrome\\\";v=\\\"103\\\", \\\"Chromium\\\";v=\\\"103\\\"\"],\"Sec-Ch-Ua-Mobile\":[\"?0\"],\"Sec-Ch-Ua-Platform\":[\"\\\"macOS\\\"\"],\"Sec-Fetch-Dest\":[\"document\"],\"Sec-Fetch-Mode\":[\"navigate\"],\"Sec-Fetch-Site\":[\"none\"],\"Sec-Fetch-User\":[\"?1\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\"],\"X-Forwarded-Host\":[\"localhost\"],\"X-Forwarded-Port\":[\"80\"],\"X-Forwarded-Proto\":[\"http\"],\"X-Forwarded-Server\":[\"57966d4b98a3\"],\"X-Real-Ip\":[\"172.21.0.1\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"localhost\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"172.21.0.1:65458\",\"RequestURI\":\"/x\",\"TLS\":null}"
my-app-traefik-1  | time="2022-08-04T18:34:40Z" level=debug msg="vulcand/oxy/roundrobin/rr: Forwarding this request to URL" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/x\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/1.1\",\"ProtoMajor\":1,\"ProtoMinor\":1,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"de,en-US;q=0.9,en;q=0.8\"],\"Connection\":[\"keep-alive\"],\"Sec-Ch-Ua\":[\"\\\".Not/A)Brand\\\";v=\\\"99\\\", \\\"Google Chrome\\\";v=\\\"103\\\", \\\"Chromium\\\";v=\\\"103\\\"\"],\"Sec-Ch-Ua-Mobile\":[\"?0\"],\"Sec-Ch-Ua-Platform\":[\"\\\"macOS\\\"\"],\"Sec-Fetch-Dest\":[\"document\"],\"Sec-Fetch-Mode\":[\"navigate\"],\"Sec-Fetch-Site\":[\"none\"],\"Sec-Fetch-User\":[\"?1\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\"],\"X-Forwarded-Host\":[\"localhost\"],\"X-Forwarded-Port\":[\"80\"],\"X-Forwarded-Proto\":[\"http\"],\"X-Forwarded-Server\":[\"57966d4b98a3\"],\"X-Real-Ip\":[\"172.21.0.1\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"localhost\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"172.21.0.1:65458\",\"RequestURI\":\"/x\",\"TLS\":null}" ForwardURL="http://172.21.0.3:3000"
my-app-traefik-1  | time="2022-08-04T18:34:40Z" level=debug msg="vulcand/oxy/roundrobin/rr: completed ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"\",\"Opaque\":\"\",\"User\":null,\"Host\":\"\",\"Path\":\"/x\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/1.1\",\"ProtoMajor\":1,\"ProtoMinor\":1,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"de,en-US;q=0.9,en;q=0.8\"],\"Connection\":[\"keep-alive\"],\"Sec-Ch-Ua\":[\"\\\".Not/A)Brand\\\";v=\\\"99\\\", \\\"Google Chrome\\\";v=\\\"103\\\", \\\"Chromium\\\";v=\\\"103\\\"\"],\"Sec-Ch-Ua-Mobile\":[\"?0\"],\"Sec-Ch-Ua-Platform\":[\"\\\"macOS\\\"\"],\"Sec-Fetch-Dest\":[\"document\"],\"Sec-Fetch-Mode\":[\"navigate\"],\"Sec-Fetch-Site\":[\"none\"],\"Sec-Fetch-User\":[\"?1\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\"],\"X-Forwarded-Host\":[\"localhost\"],\"X-Forwarded-Port\":[\"80\"],\"X-Forwarded-Proto\":[\"http\"],\"X-Forwarded-Server\":[\"57966d4b98a3\"],\"X-Real-Ip\":[\"172.21.0.1\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"localhost\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"172.21.0.1:65458\",\"RequestURI\":\"/x\",\"TLS\":null}"
my-app-traefik-1  | time="2022-08-04T18:34:40Z" level=debug msg="Caught HTTP Status Code 404, returning error page" middlewareName=http-errors@docker middlewareType=customError
my-app-traefik-1  | time="2022-08-04T18:34:40Z" level=debug msg="vulcand/oxy/roundrobin/rr: begin ServeHttp on request" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"localhost\",\"Path\":\"/test\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/1.1\",\"ProtoMajor\":1,\"ProtoMinor\":1,\"Header\":{\"Accept\":[\"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"de,en-US;q=0.9,en;q=0.8\"],\"Connection\":[\"keep-alive\"],\"Sec-Ch-Ua\":[\"\\\".Not/A)Brand\\\";v=\\\"99\\\", \\\"Google Chrome\\\";v=\\\"103\\\", \\\"Chromium\\\";v=\\\"103\\\"\"],\"Sec-Ch-Ua-Mobile\":[\"?0\"],\"Sec-Ch-Ua-Platform\":[\"\\\"macOS\\\"\"],\"Sec-Fetch-Dest\":[\"document\"],\"Sec-Fetch-Mode\":[\"navigate\"],\"Sec-Fetch-Site\":[\"none\"],\"Sec-Fetch-User\":[\"?1\"],\"Upgrade-Insecure-Requests\":[\"1\"],\"User-Agent\":[\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\"],\"X-Forwarded-Host\":[\"localhost\"],\"X-Forwarded-Port\":[\"80\"],\"X-Forwarded-Proto\":[\"http\"],\"X-Forwarded-Server\":[\"57966d4b98a3\"],\"X-Real-Ip\":[\"172.21.0.1\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"localhost\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"\",\"RequestURI\":\"/test\",\"TLS\":null}"
my-app-traefik-1  | time="2022-08-04T18:34:40Z" level=debug msg="vulcand/oxy/roundrobin/rr: Forwarding this request to URL" Request="{\"Method\":\"GET\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"localhost\",\"Path\":\"/test\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/1.1
```


Discussion / hints:
I'm experiencing the same issue. But for me, it seems to not be a general issue:

In my case, 
- if ``app1`` is a apache2 webserver, everything works good.
- if ``app1`` is a nginx, that fastcgi's to a PHP application it's working, only if the location looks as

```
location / {
    try_files $uri $uri/ =404; 
}
```

Unfortunately, if I want to run a PHP-Laravel application, the location needs to be changed in order to have routing working:
 ```
location / {
    try_files $uri $uri/ /index.php$is_args$args;
}
```

Once this is configured, I end up in the same situation: 
- Error middleware activated causes the "global" error pages from ``app2`` to be downloaded as gziped version.
- Error middleware de-activated is working: ``app1`` returns proper HTTP error responses (rendered).
 

Fix patch:
diff --git a/integration/fixtures/error_pages/simple.toml b/integration/fixtures/error_pages/simple.toml
index a734098b97..298b66a424 100644
--- a/integration/fixtures/error_pages/simple.toml
+++ b/integration/fixtures/error_pages/simple.toml
@@ -30,7 +30,7 @@
   [http.services.service1.loadBalancer]
     passHostHeader = true
     [[http.services.service1.loadBalancer.servers]]
-      url = "http://{{.Server1}}:80"
+      url = "{{.Server1}}"
 
   [http.services.error.loadBalancer]
     [[http.services.error.loadBalancer.servers]]
diff --git a/pkg/middlewares/customerrors/custom_errors.go b/pkg/middlewares/customerrors/custom_errors.go
index 58b36d1158..b24a6b04c6 100644
--- a/pkg/middlewares/customerrors/custom_errors.go
+++ b/pkg/middlewares/customerrors/custom_errors.go
@@ -233,6 +233,15 @@ func (cc *codeCatcher) Flush() {
 	// Otherwise, cc.code is actually a 200 here.
 	cc.WriteHeader(cc.code)
 
+	// We don't care about the contents of the response,
+	// since we want to serve the ones from the error page,
+	// so we just don't flush.
+	// (e.g., To prevent superfluous WriteHeader on request with a
+	// `Transfert-Encoding: chunked` header).
+	if cc.caughtFilteredCode {
+		return
+	}
+
 	if flusher, ok := cc.responseWriter.(http.Flusher); ok {
 		flusher.Flush()
 	}


Test patch:
diff --git a/integration/error_pages_test.go b/integration/error_pages_test.go
index 436b2cc96c..a9bd1c7a18 100644
--- a/integration/error_pages_test.go
+++ b/integration/error_pages_test.go
@@ -2,6 +2,7 @@ package integration
 
 import (
 	"net/http"
+	"net/http/httptest"
 	"os"
 	"time"
 
@@ -29,7 +30,7 @@ func (s *ErrorPagesSuite) TestSimpleConfiguration(c *check.C) {
 	file := s.adaptFile(c, "fixtures/error_pages/simple.toml", struct {
 		Server1 string
 		Server2 string
-	}{s.BackendIP, s.ErrorPageIP})
+	}{"http://" + s.BackendIP + ":80", s.ErrorPageIP})
 	defer os.Remove(file)
 
 	cmd, display := s.traefikCmd(withConfigFile(file))
@@ -67,3 +68,33 @@ func (s *ErrorPagesSuite) TestErrorPage(c *check.C) {
 	err = try.Request(frontendReq, 2*time.Second, try.BodyContains("An error occurred."))
 	c.Assert(err, checker.IsNil)
 }
+
+func (s *ErrorPagesSuite) TestErrorPageFlush(c *check.C) {
+	srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+		rw.Header().Add("Transfer-Encoding", "chunked")
+		rw.WriteHeader(http.StatusInternalServerError)
+		_, _ = rw.Write([]byte("KO"))
+	}))
+
+	file := s.adaptFile(c, "fixtures/error_pages/simple.toml", struct {
+		Server1 string
+		Server2 string
+	}{srv.URL, s.ErrorPageIP})
+	defer os.Remove(file)
+
+	cmd, display := s.traefikCmd(withConfigFile(file))
+	defer display(c)
+	err := cmd.Start()
+	c.Assert(err, checker.IsNil)
+	defer s.killCmd(cmd)
+
+	frontendReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080", nil)
+	c.Assert(err, checker.IsNil)
+	frontendReq.Host = "test.local"
+
+	err = try.Request(frontendReq, 2*time.Second,
+		try.BodyContains("An error occurred."),
+		try.HasHeaderValue("Content-Type", "text/html", true),
+	)
+	c.Assert(err, checker.IsNil)
+}