Repository: traefik/traefik (language: go)

Issue:
White page with no error when turn on fastProxy in Kubernetes
### 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?

When the flag `--experimental.fastProxy` is turned off, everything is fine.

System details:

* EKS v1.31
* Traefik chart v33.2.1
* Laravel swoole app (Created using https://github.com/hhxsv5/laravel-s)


### What did you see instead?

The fast proxy mode using the flag `--experimental.fastProxy` with the official helm chart causes a white page, no errors in traefik debug logs, no errors in the browser console, and the status code is 200.


### What version of Traefik are you using?

traefik:v3.2.2

### What is your environment & configuration?

Note that I am not a php developer, not sure what information should I provide.

helm chart value override

```yaml
image:
  # -- docker.io has rate limits
  registry: mirror.gcr.io

deployment:
  kind: DaemonSet # DaemonSet or Deployment
  annotations:
    reloader.stakater.com/auto: "true"

# Create an IngressRoute for the dashboard
ingressRoute:
  dashboard:
    enabled: false

providers:
  kubernetesCRD:
    allowCrossNamespace: true # Enable this to use ingress middleware from another namespace
ports:
  websecure:
    http3:
      enabled: false

service:
  spec:
    externalTrafficPolicy: Cluster # Forward X-Forwarded-For/X-Real-Ip header to pod
  annotations:
    # Use aws nlb, make sure there are multiple public subnets available in this vpc
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing

logs:
  general:
    format: common
    level: DEBUG
  access:
    enabled: true
    fields:
      defaultMode: keep
      headers:
        defaultmode: keep # Log all headers

additionalArguments:
  # - --experimental.fastProxy # Enable traefik 3.2 fastproxy mode (fasthttp), disable because it causes a white page
  - --entryPoints.websecure.proxyProtocol.insecure # Allow X-Forwarded-For
  - --entryPoints.websecure.forwardedHeaders.insecure # Trust X-Forwarded-For
```

ingress:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
    kubernetes.io/ingress.class: traefik
    kubernetes.io/tls-acme: "true"
    meta.helm.sh/release-name: app
    meta.helm.sh/release-namespace: app-dev
    traefik.ingress.kubernetes.io/preserve-host: "false"
    traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
    traefik.ingress.kubernetes.io/router.middlewares: ingress-compress@kubernetescrd
    traefik.ingress.kubernetes.io/router.tls: "true"
  creationTimestamp: "2024-12-06T11:20:13Z"
  generation: 1
  labels:
    app.kubernetes.io/managed-by: Helm
  name: app-ingress
  namespace: app-dev
  resourceVersion: "14754104"
  uid: xxxxxxxx
spec:
  rules:
  - host: app.com
    http:
      paths:
      - backend:
          service:
            name: admin
            port:
              number: 80
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - app.com
    secretName: app.com
status:
  loadBalancer:
    ingress:
    - hostname: xxx.elb.xxxx.amazonaws.com
```

middleware

```yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: compress
spec:
  compress:
    minResponseBodyBytes: 350 # Compress body bytes greater than this
    defaultEncoding: br # For performance and compatibility
    encodings: # This order matters
      - zstd
      - br
```


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

No error logs, only trace log with status code 200.


Discussion / hints:
Hey @joeky888 and thanks for the bug report,

If you or any community member can help us find verified steps to reproduce and fix the issue, we would love the help.
I have created a minimal project for this: https://github.com/joeky888/traefik-issue11437

clone it and

```fish
docker compose up --build
curl localhost:9090 # Direct access to the php app, this should be fine
curl localhost:38080 # Access through traefik
```

When the flag `--experimental.fastProxy` is turned on, the localhost:38080 response a white page.
Hello @joeky888 and thanks for the minimal project,

Could you try the latest bugfix version v3.3.2? because we fixed an issue with HEAD requests so maybe the issue you are facing is the same.
I can confirm the issue still exists after upgrading to v3.3.2. :(

Fix patch:
diff --git a/pkg/proxy/fast/connpool.go b/pkg/proxy/fast/connpool.go
index 4c0be0fe96..f2efc88b67 100644
--- a/pkg/proxy/fast/connpool.go
+++ b/pkg/proxy/fast/connpool.go
@@ -216,7 +216,9 @@ func (c *conn) handleResponse(r rwWithUpgrade) error {
 		return nil
 	}
 
-	if res.Header.ContentLength() == 0 {
+	hasContentLength := res.Header.Peek("Content-Length") != nil
+
+	if hasContentLength && res.Header.ContentLength() == 0 {
 		return nil
 	}
 
@@ -226,6 +228,20 @@ func (c *conn) handleResponse(r rwWithUpgrade) error {
 		return nil
 	}
 
+	if !hasContentLength {
+		b := c.bufferPool.Get()
+		if b == nil {
+			b = make([]byte, bufferSize)
+		}
+		defer c.bufferPool.Put(b)
+
+		if _, err := io.CopyBuffer(r.RW, c.br, b); err != nil {
+			return err
+		}
+
+		return nil
+	}
+
 	// Chunked response, Content-Length is set to -1 by FastProxy when "Transfer-Encoding: chunked" header is received.
 	if res.Header.ContentLength() == -1 {
 		cbr := httputil.NewChunkedReader(c.br)


Test patch:
diff --git a/pkg/proxy/fast/proxy_test.go b/pkg/proxy/fast/proxy_test.go
index b9f95b6069..4c4c158b17 100644
--- a/pkg/proxy/fast/proxy_test.go
+++ b/pkg/proxy/fast/proxy_test.go
@@ -306,6 +306,46 @@ func TestHeadRequest(t *testing.T) {
 	assert.Equal(t, http.StatusOK, res.Code)
 }
 
+func TestNoContentLengthResponse(t *testing.T) {
+	backendListener, err := net.Listen("tcp", ":0")
+	require.NoError(t, err)
+
+	t.Cleanup(func() {
+		_ = backendListener.Close()
+	})
+
+	go func() {
+		t.Helper()
+
+		conn, err := backendListener.Accept()
+		require.NoError(t, err)
+
+		_, err = conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\nfoo"))
+		require.NoError(t, err)
+
+		// CloseWrite the connection to signal the end of the response.
+		if v, ok := conn.(interface{ CloseWrite() error }); ok {
+			err = v.CloseWrite()
+			require.NoError(t, err)
+		}
+	}()
+
+	builder := NewProxyBuilder(&transportManagerMock{}, static.FastProxyConfig{})
+
+	serverURL := "http://" + backendListener.Addr().String()
+
+	proxyHandler, err := builder.Build("", testhelpers.MustParseURL(serverURL), true, true)
+	require.NoError(t, err)
+
+	req := httptest.NewRequest(http.MethodGet, "/", http.NoBody)
+	res := httptest.NewRecorder()
+
+	proxyHandler.ServeHTTP(res, req)
+
+	assert.Equal(t, http.StatusOK, res.Code)
+	assert.Equal(t, "foo", res.Body.String())
+}
+
 func newCertificate(t *testing.T, domain string) *tls.Certificate {
 	t.Helper()