f57eecde5e
This breaks out routing handling from `next-server`, `next-dev-server`, and `base-server` so that these are only handling the "render" work and eventually these will be deleted completely in favor of the bundling work being done. The `router` process and separate `render` processes are still maintained here although will be investigated further in follow-up to see if we can reduce the need for these. We are also changing the `require-cache` IPC to a single call instead of call per entry to reduce overhead and also de-dupes handling for starting the server between the standalone server and normal server. To maintain support for existing turbopack route resolving this implements the new route resolving in place of the existing `route-resolver` until the new nextturbo API is fully landed. After these initial changes we should continue to eliminate non-render related code from `next-server`, `base-server`, and `next-dev-server`.
311 lines
8.2 KiB
TypeScript
311 lines
8.2 KiB
TypeScript
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',
|
|
}
|
|
)
|
|
|
|
try {
|
|
expect(res.status).toBe(413)
|
|
|
|
if (!(global as any).isNextDeploy) {
|
|
expect(res.statusText).toBe('Body exceeded 1mb limit')
|
|
}
|
|
} catch (err) {
|
|
// TODO: investigate occasional EPIPE errors causing
|
|
// a 500 status instead of a 413
|
|
if (res.status !== 500) {
|
|
throw err
|
|
}
|
|
}
|
|
})
|
|
|
|
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',
|
|
}
|
|
)
|
|
|
|
try {
|
|
expect(res.status).toBe(413)
|
|
|
|
if (!(global as any).isNextDeploy) {
|
|
expect(res.statusText).toBe('Body exceeded 5kb limit')
|
|
}
|
|
} catch (err) {
|
|
// TODO: investigate occasional EPIPE errors causing
|
|
// a 500 status instead of a 413
|
|
if (res.status !== 500) {
|
|
throw err
|
|
}
|
|
}
|
|
})
|
|
|
|
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 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',
|
|
}
|
|
)
|
|
|
|
try {
|
|
expect(res.status).toBe(413)
|
|
|
|
if (!(global as any).isNextDeploy) {
|
|
expect(res.statusText).toBe('Body exceeded 5mb limit')
|
|
}
|
|
} catch (err) {
|
|
// TODO: investigate occasional EPIPE errors causing
|
|
// a 500 status instead of a 413
|
|
if (res.status !== 500) {
|
|
throw err
|
|
}
|
|
}
|
|
})
|
|
|
|
if (!(global as any).isNextDeploy) {
|
|
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)
|
|
})
|
|
})
|
|
|
|
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',
|
|
}
|
|
)
|
|
|
|
try {
|
|
expect(res.status).toBe(413)
|
|
|
|
if (!(global as any).isNextDeploy) {
|
|
expect(res.statusText).toBe('Body exceeded 5mb limit')
|
|
}
|
|
} catch (err) {
|
|
// TODO: investigate occasional EPIPE errors causing
|
|
// a 500 status instead of a 413
|
|
if (res.status !== 500) {
|
|
throw err
|
|
}
|
|
}
|
|
})
|
|
})
|