Files

60 lines
1.5 KiB
JavaScript

export async function readRequestBody(req, limitBytes) {
const chunks = [];
let size = 0;
for await (const chunk of req) {
size += chunk.length;
if (size > limitBytes) {
const error = new Error('Request body is too large');
error.status = 413;
throw error;
}
chunks.push(chunk);
}
return Buffer.concat(chunks);
}
export function parseMultipart(buffer, contentType) {
const match = /boundary=(?:"([^"]+)"|([^;]+))/i.exec(contentType || '');
if (!match) {
const error = new Error('Missing multipart boundary');
error.status = 400;
throw error;
}
const boundary = `--${match[1] || match[2]}`;
const binary = buffer.toString('binary');
const parts = [];
for (const raw of binary.split(boundary)) {
if (!raw || raw === '--\r\n' || raw === '--') {
continue;
}
const trimmed = raw.replace(/^\r\n/, '').replace(/\r\n--$/, '');
const separator = trimmed.indexOf('\r\n\r\n');
if (separator === -1) {
continue;
}
const headerText = trimmed.slice(0, separator);
let bodyText = trimmed.slice(separator + 4);
if (bodyText.endsWith('\r\n')) {
bodyText = bodyText.slice(0, -2);
}
const disposition = /content-disposition:\s*form-data;\s*([^\r\n]+)/i.exec(headerText)?.[1] || '';
const name = /name="([^"]+)"/i.exec(disposition)?.[1] || '';
const filename = /filename="([^"]*)"/i.exec(disposition)?.[1] || '';
parts.push({
name,
filename,
data: Buffer.from(bodyText, 'binary')
});
}
return parts;
}