204/304 responses should not send body or Content-Length (RFC 9112 compliance)
Currently, Gunicorn forwards 204 and 304 responses even when the app includes a non-zero Content-Length or a body.
According to RFC 9112 , these responses must not include a message body, and Content-Length must be absent or zero.
Expected behavior
For 1xx, 204, 304 responses (and HEAD requests):
- Any response body should be ignored or dropped.
Content-Lengthshould be removed.
Actual behavior
Gunicorn sends the body and headers as provided by the WSGI app, even when they violate the spec.
Thank you for opening the issue @JaeHyuckSa . I discovered this issue when I deployed it on AWS. I deployed an API that included a body along with a 204 response, and it caused a 502 Gateway Error. All other web frameworks handle this correctly by sending 204 responses without a body and no errors, but it seems only Django behaves this way.
In my opinion, this needs to be fixed. If a fix is indeed necessary, I would like to work on it.
Here is a comparison of how different frameworks behave when dealing with 204 responses:
- Spring: Does not accept data at all (no parameter for data)
- Express: Data is removed and Content-Length is not sent
- NestJS: Data is removed and Content-Length is not sent
- Flask: Data is removed and Content-Length is not sent
- FastAPI: Data is removed and Content-Length is not sent
- Django: Data is removed, but Content-Length is sent
what should return gunicorn if the app insist to send it ?
@benoitc Thanks for the question. According to RFC 9112, for 204 and 304 responses, Gunicorn should enforce the spec by:
- Ignoring/dropping any provided response body entirely.
- Removing the Content-Length header (or setting it to 0 if required, but preferably removing it to avoid confusion).
This ensures compliance even if the WSGI app tries to send invalid content. As seen in other frameworks (e.g., Flask removes the body and omits Content-Length), this prevents issues like 502 errors on AWS. If we don't enforce this, it could lead to downstream problems, such as corrupted responses or gateway errors. I'd suggest adding logic in the response handler to filter based on status code. Happy to discuss or contribute a PR for this!