fix(gateway): enforce request body size limits
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import type { IncomingMessage } from 'http';
|
||||
|
||||
export interface ReadRequestBodyOptions {
|
||||
maxBytes: number;
|
||||
}
|
||||
|
||||
export class RequestBodyTooLargeError extends Error {
|
||||
readonly maxBytes: number;
|
||||
readonly receivedBytes: number;
|
||||
|
||||
constructor(maxBytes: number, receivedBytes: number) {
|
||||
super(`Request body too large (${receivedBytes} bytes > ${maxBytes} bytes)`);
|
||||
this.name = 'RequestBodyTooLargeError';
|
||||
this.maxBytes = maxBytes;
|
||||
this.receivedBytes = receivedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/** Read the full request body with an explicit max-size limit. */
|
||||
export function readRequestBody(req: IncomingMessage, opts: ReadRequestBodyOptions): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks: Buffer[] = [];
|
||||
let totalBytes = 0;
|
||||
let settled = false;
|
||||
|
||||
const cleanup = () => {
|
||||
req.off('data', onData);
|
||||
req.off('end', onEnd);
|
||||
req.off('error', onError);
|
||||
};
|
||||
|
||||
const fail = (err: Error) => {
|
||||
if (settled) {return;}
|
||||
settled = true;
|
||||
cleanup();
|
||||
reject(err);
|
||||
};
|
||||
|
||||
const onData = (chunk: Buffer | string) => {
|
||||
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
||||
totalBytes += buf.length;
|
||||
if (totalBytes > opts.maxBytes) {
|
||||
if (typeof req.destroy === 'function') {
|
||||
req.destroy();
|
||||
}
|
||||
fail(new RequestBodyTooLargeError(opts.maxBytes, totalBytes));
|
||||
return;
|
||||
}
|
||||
chunks.push(buf);
|
||||
};
|
||||
|
||||
const onEnd = () => {
|
||||
if (settled) {return;}
|
||||
settled = true;
|
||||
cleanup();
|
||||
resolve(Buffer.concat(chunks).toString('utf-8'));
|
||||
};
|
||||
|
||||
const onError = (err: Error) => fail(err);
|
||||
|
||||
req.on('data', onData);
|
||||
req.on('end', onEnd);
|
||||
req.on('error', onError);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user