UNPKG

kequapp

Version:

A minimal, zero-magic Node web framework built on native APIs

70 lines (69 loc) 2.19 kB
import Ex from "../../built-in/tools/ex.js"; import headerAttributes from "../../util/header-attributes.js"; const CR = 0x0d; const LF = 0x0a; export default function splitMultipart(body) { const contentType = body.headers['content-type']; if (!contentType?.startsWith('multipart/')) { throw Ex.BadRequest('Unable to process request', { contentType, }); } const boundary = extractBoundary(contentType); const buffer = body.data; const result = []; let headers = {}; let i = findNextLine(buffer, buffer.indexOf(boundary, 0)); function addHeader(nextLine) { const line = buffer.slice(i, nextLine).toString(); const parts = line.split(':'); const key = parts[0].trim().toLowerCase(); const value = parts[1]?.trim(); if (key && value) headers[key] = value; } function addPart(nextBoundary) { const dataEnd = nextBoundary - (buffer[nextBoundary - 2] === CR ? 2 : 1); result.push({ headers, data: buffer.slice(i, dataEnd), }); headers = {}; } while (i > -1) { // until two new lines while (i > -1 && buffer[i] !== CR && buffer[i] !== LF) { const nextLine = findNextLine(buffer, i); if (nextLine > -1) addHeader(nextLine); i = nextLine; } if (i < 0) break; i += buffer[i] === CR ? 2 : 1; if (i >= buffer.length) break; // data start const nextBoundary = buffer.indexOf(boundary, i); if (nextBoundary < 0) break; addPart(nextBoundary); i = findNextLine(buffer, nextBoundary); } return result; } function extractBoundary(contentType) { const boundary = headerAttributes(contentType).boundary; if (!boundary) { throw Ex.BadRequest('Multipart request requires boundary attribute', { contentType, }); } return `--${boundary}`; } function findNextLine(buffer, from) { const i = buffer.indexOf(LF, from) + 1; if (i < 1 || i >= buffer.length) return -1; return i; }