Skip to content

Commit

Permalink
Fix handling for 204 status code with a body (#28479)
Browse files Browse the repository at this point in the history
This ensures we handle 204 and 304 status codes correctly in API routes.  

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Errors have helpful link attached, see `contributing.md`

Fixes: #28464
  • Loading branch information
ijjk committed Aug 25, 2021
1 parent f216855 commit ead10f1
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 0 deletions.
32 changes: 32 additions & 0 deletions errors/invalid-api-status-body.md
@@ -0,0 +1,32 @@
Invalid API Route Status/Body Response

#### Why This Error Occurred

In one of your API routes a 204 or 304 status code was used as well as sending a response body.

This is invalid as a 204 or 304 status code dictates no response body should be present.

#### Possible Ways to Fix It

Send an empty body when using a 204 or 304 status code or use a different status code while sending a response body.

Before

```js
export default function handler(req, res) {
res.status(204).send('invalid body')
}
```

After

```js
export default function handler(req, res) {
res.status(204).send()
}
```

### Useful Links

- [204 status code documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204)
- [304 status code documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304)
4 changes: 4 additions & 0 deletions errors/manifest.json
Expand Up @@ -454,6 +454,10 @@
{
"title": "next-config-error",
"path": "/errors/next-config-error.md"
},
{
"title": "invalid-api-status-body",
"path": "/errors/invalid-api-status-body.md"
}
]
}
Expand Down
16 changes: 16 additions & 0 deletions packages/next/server/api-utils.ts
Expand Up @@ -258,6 +258,22 @@ export function sendData(
return
}

// strip irrelevant headers/body
if (res.statusCode === 204 || res.statusCode === 304) {
res.removeHeader('Content-Type')
res.removeHeader('Content-Length')
res.removeHeader('Transfer-Encoding')

if (process.env.NODE_ENV === 'development' && body) {
console.warn(
`A body was attempted to be set with a 204 statusCode for ${req.url}, this is invalid and the body was ignored.\n` +
`See more info here https://nextjs.org/docs/messages/invalid-api-status-body`
)
}
res.end()
return
}

const contentType = res.getHeader('Content-Type')

if (body instanceof Stream) {
Expand Down
7 changes: 7 additions & 0 deletions test/integration/api-support/pages/api/status-204.js
@@ -0,0 +1,7 @@
export default function handler(req, res) {
if (req.query.invalid) {
// test the warning when content is added for a 204 response
return res.status(204).json({ hello: 'world' })
}
return res.status(204).send()
}
30 changes: 30 additions & 0 deletions test/integration/api-support/test/index.test.js
Expand Up @@ -26,6 +26,36 @@ let mode
let app

function runTests(dev = false) {
it('should handle 204 status correctly', async () => {
const res = await fetchViaHTTP(appPort, '/api/status-204', undefined, {
redirect: 'manual',
})
expect(res.status).toBe(204)
expect(res.headers.get('content-type')).toBe(null)
expect(res.headers.get('content-length')).toBe(null)
expect(res.headers.get('transfer-encoding')).toBe(null)

const stderrIdx = stderr.length
const res2 = await fetchViaHTTP(
appPort,
'/api/status-204',
{ invalid: '1' },
{
redirect: 'manual',
}
)
expect(res2.status).toBe(204)
expect(res2.headers.get('content-type')).toBe(null)
expect(res2.headers.get('content-length')).toBe(null)
expect(res2.headers.get('transfer-encoding')).toBe(null)

if (dev) {
expect(stderr.substr(stderrIdx)).toContain(
'A body was attempted to be set with a 204 statusCode'
)
}
})

it('should render page', async () => {
const html = await renderViaHTTP(appPort, '/')
expect(html).toMatch(/API - support/)
Expand Down

0 comments on commit ead10f1

Please sign in to comment.