Closed
Description
It seems that HTTP 204 and 205 responses should not have a response body:
res.sendStatus(204)
correctly returns no response body, but res.sendStatus(205)
returns a Reset Content
string. Is this expected?
How to reproduce
require('express')()
.get('/204', (req, res) => res.sendStatus(204))
.get('/205', (req, res) => res.sendStatus(205))
.listen(8080, () => console.log('Ready'))
$ curl http://localhost:8080/204
$ curl http://localhost:8080/205
Reset Content
$ curl -I -XGET http://192.168.100.232:8080/204
HTTP/1.1 204 No Content
X-Powered-By: Express
ETag: W/"a-bAsFyilMr4Ra1hIU5PyoyFRunpI"
Date: Sun, 16 May 2021 12:26:18 GMT
Connection: keep-alive
Keep-Alive: timeout=5
$ curl -I -XGET http://192.168.100.232:8080/205
HTTP/1.1 205 Reset Content
X-Powered-By: Express
Content-Type: text/plain; charset=utf-8
Content-Length: 13
ETag: W/"d-yL62EER5Ke7tFugRpssh46aJ7As"
Date: Sun, 16 May 2021 12:26:25 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Express version: 4.17.1
Node.js version: 15.14.0
Metadata
Metadata
Assignees
Labels
No labels
Activity
dougwilson commentedon May 16, 2021
Thank you for the report! It looks like Express can only fix part of the issue, unfortunately. We can change it to send an empty body, but cannot send no body at all. This is because Node.js does not procide an API to send no body, instead sending a zero length body at minimum, which violates the spec: https://datatracker.ietf.org/doc/html/rfc7231#section-6.3.6
If having the body is messing up the client, the change in Express is unlikely to be a complete fix and Node.js would also need to add 205 to the list of status codes that must not have a response body.
https://github.com/nodejs/node/blob/82eddca23d35bcf779d9d1905744cc9cfa6ad9a0/lib/_http_server.js#L327
https://github.com/nodejs/node/blob/82eddca23d35bcf779d9d1905744cc9cfa6ad9a0/lib/_http_outgoing.js#L462
dougwilson commentedon May 16, 2021
Apologies, I just reread 205 and apparently it is slightly different from 204 and 304, in that it does have a payload, but just must be zero length. We can fix that here, but still can only guarantee the fix as long as the users use the Express methods like res.send, res.json, etc. Using res.end and res.write would require Node.js to add a rule as those methods are delivered by the Node.js framework.
tkesgar commentedon May 16, 2021
Oops, I missed the details for HTTP 205. I thought it should behave exactly like 204 🐧
I think that is a fair deal, since users wanting to send HTTP 205 would probably use
res.sendStatus(205)
, sinceres.send(205)
will show the deprecation message.This is a workaround for now I think:
tkesgar commentedon May 20, 2021
I tried some fix at #4596.
While it matches the spec (send a
Content-Length: 0
and empty chunk), I am still unsure if that is the best way to handle this.Support proper 205 responses using res.send
Support proper 205 responses using res.send
everhardt commentedon Jun 23, 2022
This is a breaking change that hurt our production services. I see expressjs is following semver, shouldn't this have increased the major number?
Also, there's currently no way to disable this new functionality
everhardt commentedon Jun 23, 2022
Would you consider a PR that adds a parameter
strict = true
to the signature of.send
, so that it becomes.send(body, strict = true)
? Forstrict === false
, we would then not do the 204/205-specific cleaning actions.dougwilson commentedon Jun 23, 2022
Hi @everhardt thank you for the feedback. Yes, Express.js uses semver, but sometimes fixing bugs is a hard choice. Express.js considers violations of the HTTP specs to be bugs and the prior behavior, as pointed out by the OP, violated the HTTP spec so we fixed that bug.
You can skip this functionality by using the underlying
.write
/.end
methods, at least until Node.js also releases a fix to stop sending a body for a 205 response.