import { configureHttpBodyParsers, DEFAULT_JSON_BODY_LIMIT, IMPORT_JSON_BODY_LIMIT } from './http-body-limits'; const express = require('express') as () => { use(...args: unknown[]): void; post(path: string, handler: (request: { body?: unknown; rawBody?: Buffer }, response: { json(body: unknown): void }) => void): void; listen(port: number, host: string, callback: () => void): { close(callback: (error?: Error) => void): void; address(): { port: number } | string | null }; }; const expressModule = require('express') as { json(options: { limit: string }): (...args: unknown[]) => unknown; urlencoded(options: { limit: string; extended: boolean }): (...args: unknown[]) => unknown }; const http = require('node:http') as typeof import('node:http'); describe('configureHttpBodyParsers', () => { it('keeps ordinary JSON bounded while granting only import routes a larger limit', () => { const use = jest.fn(); const useBodyParser = jest.fn(); configureHttpBodyParsers({ use, useBodyParser } as never); expect(DEFAULT_JSON_BODY_LIMIT).toBe('2mb'); expect(IMPORT_JSON_BODY_LIMIT).toBe('25mb'); expect(use).toHaveBeenCalledTimes(1); expect(use).toHaveBeenCalledWith('/api/client/send/imports', expect.any(Function)); expect(useBodyParser).toHaveBeenNthCalledWith(1, 'json', { limit: '2mb' }); expect(useBodyParser).toHaveBeenNthCalledWith(2, 'urlencoded', { limit: '2mb', extended: true }); }); it('accepts a 3 MiB import JSON body but rejects the same ordinary JSON body', async () => { const serverApp = express(); configureHttpBodyParsers({ use: serverApp.use.bind(serverApp), useBodyParser(type: 'json' | 'urlencoded', options: { limit: string; extended?: boolean }) { serverApp.use(type === 'json' ? expressModule.json({ limit: options.limit }) : expressModule.urlencoded({ limit: options.limit, extended: options.extended ?? true })); }, } as never); serverApp.post('/api/client/send/imports/preview', (request, response) => response.json({ size: request.rawBody?.length ?? 0 })); serverApp.post('/api/ordinary', (_request, response) => response.json({ accepted: true })); const server = await new Promise>((resolve) => { const listening = serverApp.listen(0, '127.0.0.1', () => resolve(listening)); }); try { const address = server.address(); if (!address || typeof address === 'string') throw new Error('test server did not expose a TCP port'); const body = JSON.stringify({ content: 'x'.repeat(3 * 1024 * 1024) }); const importResponse = await postJSON(address.port, '/api/client/send/imports/preview', body); expect(importResponse.status).toBe(200); expect(JSON.parse(importResponse.body)).toEqual({ size: Buffer.byteLength(body) }); await expect(postJSON(address.port, '/api/ordinary', body)).resolves.toMatchObject({ status: 413 }); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } }); }); function postJSON(port: number, path: string, body: string) { return new Promise<{ status: number; body: string }>((resolve, reject) => { const request = http.request({ hostname: '127.0.0.1', port, path, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } }, (response) => { const chunks: Buffer[] = []; response.on('data', (chunk: Buffer) => chunks.push(chunk)); response.once('end', () => resolve({ status: response.statusCode ?? 0, body: Buffer.concat(chunks).toString('utf8') })); }); request.once('error', reject); request.end(body); }); }