Repository: traefik/traefik (language: go)

Issue:
maxResponseBodyBytes exceed doesn't change response code to 500
### 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 setup a response size limit, see https://doc.traefik.io/traefik/middlewares/http/buffering/#maxresponsebodybytes.

### What did you see instead?

Trimmed with maxResponseBodyBytes response body and 200 status code.

### What version of Traefik are you using?

2.11.2

### What is your environment & configuration?

- traefik.http.routers.backend.middlewares=limit@docker
- traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=2000000

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

_No response_


Discussion / hints:
Hey @AliaksandrZhloba,

Thanks for reaching out.

Could you provide a minimal reproducible case (for instance, full Kubernetes manifest to reproduce the issue)?

In the meantime, if any community member can help us find verified steps to reproduce and fix the issue if possible, we would love the help.

Hello @nmengin ,

docker-compose.yml:
```
services:
  reverse-proxy:
    image: traefik:v2.11.2
    command: --api.insecure=true --providers.docker --entryPoints.web.address=:80 --entryPoints.websecure.address=:443
    ports:
      - "80:80"
      - "8080:8080"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  backend:
    image: ealen/echo-server
    labels:
      - traefik.http.routers.backend.rule=Host(`echo.docker.localhost`) || PathPrefix(`/echo`)
      - traefik.http.routers.backend.entrypoints=web
      - traefik.http.services.backend.loadbalancer.server.port=80
      - traefik.http.routers.backend.middlewares=limit@docker
      - traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=20000
```

POST echo.docker.localhost with any large body.

Tried _web_ and _websecure_ entrypoints - the result is the same.
Tried v2.11.2 and v3.0.0 - similar (although v3.0.0 sometimes writes `ERR write: total size of 32768 exceeded allowed 20000 entryPointName=web middlewareName=limit@docker middlewareType=Buffer routerName=backend@docker` to log).
When maxResponseBodyBytes=2000 - the response is 500 Internal Server Error
When maxResponseBodyBytes=20000 - the response is 200, by the body is not only trimmed but sometimes contains some trash.
Hey @AliaksandrZhloba,

Thanks for the additional information.
If any community member can help us to move forward on it, we would love the help.

I can take a look at this issue.


I looked into this a bit. I wasn't completely sure about the behavior of the `ealen/echo-server` mentioned above, so I wrote a small server that returns responses of a requested size and put it behind a traefik instance using  the docker-compose.yml above. The project and logs from requesting response sizes from 1 up to ~200000 bytes are available at https://github.com/adamvduke/size-server

I came across some interesting behavior where the buffer changes from returning a 200 to a 500 depending on the configured limits, but then also changes back and forth when crossing a response size equal to a multiple of 32768 bytes.

For instance, this issue configures a buffer that sets the maxResponseBodyBytes option to a value of 2000 bytes. For response sizes from 1 up to 2000 bytes, the buffer behaves correctly and returns a 200 status which is expected. From 2001 up to 32768, the buffer returns a 500 status which is also expected. From 32769 up to 34769 (32769 + 2000) the buffer changes back to returning a 200 status, which I don't think is the expected behavior. From 34769 up to 65538 the behavior changes back to a 500, and so on at size boundaries equal to multiples of 32768.

I believe this behavior is caused by a bug in an underlying dependency. Either https://github.com/vulcand/oxy or https://github.com/mailgun/multibuf

I created https://github.com/vulcand/oxy/pull/247 which adds a handful of test cases, some of which are currently broken, that replicate the behavior reported in this issue. I haven't found the cause, but this error check does make me pause. https://github.com/vulcand/oxy/blob/c232cee41dd0dfb946a3d1ace7001b797e69ed14/buffer/buffer.go#L296-L301

I haven't yet been able to create a test that replicates the issue in mailgun/multibuf which vulcand/oxy depends on.

Hopefully some of the research here, in https://github.com/adamvduke/size-server, or https://github.com/vulcand/oxy/pull/247 can point someone in the correct direction to finding the root cause.
Hey @adamvduke,

Thank you for the analysis.
I put the issue on the maintainers' plate to check the tests you have created and move forward.

We'll keep you updated following up on this issue.
I pushed a commit to https://github.com/vulcand/oxy/pull/247 which may be of interest. It fixes the test cases that I added to that PR. I don't have a great workflow setup for testing the whole traefik -> vulcand/oxy -> mailgun stack with local modifications at the moment.
Hey @AliaksandrZhloba - I was able to replicate the issue you mentioned 

```shell
 ✘ dfs@illidan  ~/  curl -i -X POST http://echo.docker.localhost/echo -d "$(printf 'A%.0s' {1..20000})" -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Host echo.docker.localhost:80 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:80...
* Connected to echo.docker.localhost (::1) port 80
> POST /echo HTTP/1.1
> Host: echo.docker.localhost
> User-Agent: curl/8.9.1
> Accept: */*
> Content-Length: 20000
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 20000 bytes
< HTTP/1.1 500 Internal Server Error
HTTP/1.1 500 Internal Server Error
< Date: Tue, 18 Mar 2025 20:04:57 GMT
Date: Tue, 18 Mar 2025 20:04:57 GMT
< Content-Length: 21
Content-Length: 21
< Content-Type: text/plain; charset=utf-8
Content-Type: text/plain; charset=utf-8
< 

* Connection #0 to host echo.docker.localhost left intact
Internal Server Error%                                                                                                                                                                                                                                          dfs@illidan  ~/  
``` 

It's intermittent though. Sometimes I get a 500, sometimes I get 200.

Would you be able to tell which curl command you ran and if it's always 500 you get as response?

Fix patch:
diff --git a/go.mod b/go.mod
index 989743fd70..167a60557f 100644
--- a/go.mod
+++ b/go.mod
@@ -29,7 +29,7 @@ require (
 	github.com/golang/protobuf v1.5.4
 	github.com/google/go-github/v28 v28.1.1
 	github.com/gorilla/mux v1.8.1
-	github.com/gorilla/websocket v1.5.0
+	github.com/gorilla/websocket v1.5.3
 	github.com/hashicorp/consul/api v1.26.1
 	github.com/hashicorp/go-hclog v1.6.3
 	github.com/hashicorp/go-multierror v1.1.1
@@ -69,7 +69,7 @@ require (
 	github.com/uber/jaeger-lib v2.4.1+incompatible
 	github.com/unrolled/render v1.0.2
 	github.com/unrolled/secure v1.0.9
-	github.com/vulcand/oxy/v2 v2.0.0
+	github.com/vulcand/oxy/v2 v2.0.3
 	github.com/vulcand/predicate v1.2.0
 	go.elastic.co/apm/module/apmot/v2 v2.4.8
 	go.elastic.co/apm/v2 v2.4.8
diff --git a/go.sum b/go.sum
index 8ab9081951..e8cc4fc7c1 100644
--- a/go.sum
+++ b/go.sum
@@ -638,8 +638,8 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
 github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf h1:C1GPyPJrOlJlIrcaBBiBpDsqZena2Ks8spa5xZqr1XQ=
 github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf/go.mod h1:zXqxTI6jXDdKnlf8s+nT+3c8LrwUEy3yNpO4XJL90lA=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
@@ -1344,8 +1344,8 @@ github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
 github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60=
 github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
-github.com/vulcand/oxy/v2 v2.0.0 h1:V+scHhd2xBjO8ojBRgxCM+OdZxRA/YTs8M70w5tdNy8=
-github.com/vulcand/oxy/v2 v2.0.0/go.mod h1:uIAz3sYafO7i+V3SC8oDlMn/lt1i9aWcyXuXqVswKzE=
+github.com/vulcand/oxy/v2 v2.0.3 h1:CPWVPfW4hVZXzwwiQzpFidbnJKpahjPHezM+7TkZRNw=
+github.com/vulcand/oxy/v2 v2.0.3/go.mod h1:k3t+xjyqmXVh88FdFDbYmUKMEvNpaejvBW14es6H70A=
 github.com/vulcand/predicate v1.2.0 h1:uFsW1gcnnR7R+QTID+FVcs0sSYlIGntoGOTb3rQJt50=
 github.com/vulcand/predicate v1.2.0/go.mod h1:VipoNYXny6c8N381zGUWkjuuNHiRbeAZhE7Qm9c+2GA=
 github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=


Test patch: