Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(stream): Allows body larger than 16 KiB with middleware
- Loading branch information
1 parent
fb30be4
commit e08c2a3
Showing
3 changed files
with
326 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
import { createNext } from 'e2e-utils' | ||
import { NextInstance } from 'test/lib/next-modes/base' | ||
import { fetchViaHTTP } from 'next-test-utils' | ||
|
||
describe('Middleware fetches with body', () => { | ||
let next: NextInstance | ||
|
||
beforeAll(async () => { | ||
next = await createNext({ | ||
files: { | ||
'pages/api/default.js': ` | ||
export default (req, res) => res.json({ body: req.body }) | ||
`, | ||
'pages/api/size_limit_5kb.js': ` | ||
export const config = { api: { bodyParser: { sizeLimit: '5kb' } } } | ||
export default (req, res) => res.json({ body: req.body }) | ||
`, | ||
'pages/api/size_limit_5mb.js': ` | ||
export const config = { api: { bodyParser: { sizeLimit: '5mb' } } } | ||
export default (req, res) => res.json({ body: req.body }) | ||
`, | ||
'pages/api/body_parser_false.js': ` | ||
export const config = { api: { bodyParser: false } } | ||
async function buffer(readable) { | ||
const chunks = [] | ||
for await (const chunk of readable) { | ||
chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk) | ||
} | ||
return Buffer.concat(chunks) | ||
} | ||
export default async (req, res) => { | ||
const buf = await buffer(req) | ||
const rawBody = buf.toString('utf8'); | ||
res.json({ rawBody, body: req.body }) | ||
} | ||
`, | ||
'middleware.js': ` | ||
import { NextResponse } from 'next/server'; | ||
export default async (req) => NextResponse.next(); | ||
`, | ||
}, | ||
dependencies: {}, | ||
}) | ||
}) | ||
afterAll(() => next.destroy()) | ||
|
||
describe('with default bodyParser sizeLimit (1mb)', () => { | ||
it('should return 413 for body greater than 1mb', async () => { | ||
const bodySize = 1024 * 1024 + 1 | ||
const body = 'r'.repeat(bodySize) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/default', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
|
||
expect(res.status).toBe(413) | ||
expect(res.statusText).toBe('Body exceeded 1mb limit') | ||
}) | ||
|
||
it('should be able to send and return body size equal to 1mb', async () => { | ||
const bodySize = 1024 * 1024 | ||
const body = 'B1C2D3E4F5G6H7I8J9K0LaMbNcOdPeQf'.repeat(bodySize / 32) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/default', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
const data = await res.json() | ||
|
||
expect(res.status).toBe(200) | ||
expect(data.body.length).toBe(bodySize) | ||
expect(data.body.split('B1C2D3E4F5G6H7I8J9K0LaMbNcOdPeQf').length).toBe( | ||
bodySize / 32 + 1 | ||
) | ||
}) | ||
|
||
it('should be able to send and return body greater than default highWaterMark (16KiB)', async () => { | ||
const bodySize = 16 * 1024 + 1 | ||
const body = | ||
'CD1E2F3G4H5I6J7K8L9M0NaObPcQdReS'.repeat(bodySize / 32) + 'C' | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/default', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
const data = await res.json() | ||
|
||
expect(res.status).toBe(200) | ||
expect(data.body.length).toBe(bodySize) | ||
expect(data.body.split('CD1E2F3G4H5I6J7K8L9M0NaObPcQdReS').length).toBe( | ||
512 + 1 | ||
) | ||
}) | ||
}) | ||
|
||
describe('with custom bodyParser sizeLimit (5kb)', () => { | ||
it('should return 413 for body greater than 5kb', async () => { | ||
const bodySize = 5 * 1024 + 1 | ||
const body = 's'.repeat(bodySize) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/size_limit_5kb', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
|
||
expect(res.status).toBe(413) | ||
expect(res.statusText).toBe('Body exceeded 5kb limit') | ||
}) | ||
|
||
it('should be able to send and return body size equal to 5kb', async () => { | ||
const bodySize = 5120 | ||
const body = 'DEF1G2H3I4J5K6L7M8N9O0PaQbRcSdTe'.repeat(bodySize / 32) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/size_limit_5kb', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
const data = await res.json() | ||
|
||
expect(res.status).toBe(200) | ||
expect(data.body.length).toBe(bodySize) | ||
expect(data.body.split('DEF1G2H3I4J5K6L7M8N9O0PaQbRcSdTe').length).toBe( | ||
bodySize / 32 + 1 | ||
) | ||
}) | ||
}) | ||
|
||
describe('with custom bodyParser sizeLimit (5mb)', () => { | ||
it('should return 413 for body equal to 10mb', async () => { | ||
const bodySize = 10 * 1024 * 1024 | ||
const body = 't'.repeat(bodySize) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/size_limit_5mb', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
|
||
expect(res.status).toBe(413) | ||
expect(res.statusText).toBe('Body exceeded 5mb limit') | ||
}) | ||
|
||
it('should return 413 for body greater than 5mb', async () => { | ||
const bodySize = 5 * 1024 * 1024 + 1 | ||
const body = 'u'.repeat(bodySize) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/size_limit_5mb', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
|
||
expect(res.status).toBe(413) | ||
expect(res.statusText).toBe('Body exceeded 5mb limit') | ||
}) | ||
|
||
it('should be able to send and return body size equal to 5mb', async () => { | ||
const bodySize = 5 * 1024 * 1024 | ||
const body = 'FGHI1J2K3L4M5N6O7P8Q9R0SaTbUcVdW'.repeat(bodySize / 32) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/size_limit_5mb', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
const data = await res.json() | ||
|
||
expect(res.status).toBe(200) | ||
expect(data.body.length).toBe(bodySize) | ||
expect(data.body.split('FGHI1J2K3L4M5N6O7P8Q9R0SaTbUcVdW').length).toBe( | ||
bodySize / 32 + 1 | ||
) | ||
}) | ||
}) | ||
|
||
describe('with bodyParser = false', () => { | ||
it('should be able to send and return with body size equal to 16KiB', async () => { | ||
const bodySize = 16 * 1024 | ||
const body = 'HIJK1L2M3N4O5P6Q7R8S9T0UaVbWcXdY'.repeat(bodySize / 32) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/body_parser_false', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
const data = await res.json() | ||
|
||
expect(res.status).toBe(200) | ||
expect(data.body).toBeUndefined() | ||
expect(data.rawBody.length).toBe(bodySize) | ||
expect( | ||
data.rawBody.split('HIJK1L2M3N4O5P6Q7R8S9T0UaVbWcXdY').length | ||
).toBe(bodySize / 32 + 1) | ||
}) | ||
|
||
it('should be able to send and return with body greater than 16KiB', async () => { | ||
const bodySize = 1024 * 1024 | ||
const body = 'JKLM1N2O3P4Q5R6S7T8U9V0WaXbYcZdA'.repeat(bodySize / 32) | ||
|
||
const res = await fetchViaHTTP( | ||
next.url, | ||
'/api/body_parser_false', | ||
{}, | ||
{ | ||
body, | ||
method: 'POST', | ||
} | ||
) | ||
const data = await res.json() | ||
|
||
expect(res.status).toBe(200) | ||
expect(data.body).toBeUndefined() | ||
expect(data.rawBody.length).toBe(bodySize) | ||
expect( | ||
data.rawBody.split('JKLM1N2O3P4Q5R6S7T8U9V0WaXbYcZdA').length | ||
).toBe(bodySize / 32 + 1) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters