@wooksjs/http-body
Version:
@wooksjs/http-body
149 lines (145 loc) • 5.38 kB
JavaScript
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
const __wooksjs_event_http = __toESM(require("@wooksjs/event-http"));
//#region packages/http-body/src/utils/safe-json.ts
const ILLEGAL_KEYS = [
"__proto__",
"constructor",
"prototype"
];
const illigalKeySet = new Set(ILLEGAL_KEYS);
function safeJsonParse(src) {
return JSON.parse(src, (key, value) => {
assertKey(key);
return value;
});
}
function assertKey(k) {
if (illigalKeySet.has(k)) throw new __wooksjs_event_http.HttpError(400, `Illegal key name "${k}"`);
}
//#endregion
//#region packages/http-body/src/body.ts
function useBody() {
const { store } = (0, __wooksjs_event_http.useHttpContext)();
const { init } = store("request");
const { rawBody } = (0, __wooksjs_event_http.useRequest)();
const { "content-type": contentType } = (0, __wooksjs_event_http.useHeaders)();
function contentIs(type) {
return (contentType || "").includes(type);
}
const isJson = () => init("isJson", () => contentIs("application/json"));
const isHtml = () => init("isHtml", () => contentIs("text/html"));
const isXml = () => init("isXml", () => contentIs("text/xml"));
const isText = () => init("isText", () => contentIs("text/plain"));
const isBinary = () => init("isBinary", () => contentIs("application/octet-stream"));
const isFormData = () => init("isFormData", () => contentIs("multipart/form-data"));
const isUrlencoded = () => init("isUrlencoded", () => contentIs("application/x-www-form-urlencoded"));
const parseBody = () => init("parsed", async () => {
const body = await rawBody();
const sBody = body.toString();
if (isJson()) return jsonParser(sBody);
else if (isFormData()) return formDataParser(sBody);
else if (isUrlencoded()) return urlEncodedParser(sBody);
else if (isBinary()) return textParser(sBody);
else return textParser(sBody);
});
function jsonParser(v) {
try {
return safeJsonParse(v);
} catch (error) {
throw new __wooksjs_event_http.HttpError(400, error.message);
}
}
function textParser(v) {
return v;
}
function formDataParser(v) {
const MAX_PARTS = 255;
const MAX_KEY_LENGTH = 100;
const MAX_VALUE_LENGTH = 100 * 1024;
const boundary = `--${(/boundary=([^;]+)(?:;|$)/u.exec(contentType || "") || [, ""])[1]}`;
if (!boundary) throw new __wooksjs_event_http.HttpError(__wooksjs_event_http.EHttpStatusCode.BadRequest, "form-data boundary not recognized");
const parts = v.trim().split(boundary);
const result = Object.create(null);
let key = "";
let partContentType = "text/plain";
let partCount = 0;
for (const part of parts) {
parsePart();
key = "";
partContentType = "text/plain";
if (!part.trim() || part.trim() === "--") continue;
partCount++;
if (partCount > MAX_PARTS) throw new __wooksjs_event_http.HttpError(413, "Too many form fields");
let valueMode = false;
const lines = part.trim().split(/\n/u).map((l) => l.trim());
for (const line of lines) {
if (valueMode) {
if (line.length + String(result[key] ?? "").length > MAX_VALUE_LENGTH) throw new __wooksjs_event_http.HttpError(413, `Field "${key}" is too large`);
result[key] = (result[key] ? `${result[key]}\n` : "") + line;
continue;
}
if (!line) {
valueMode = !!key;
continue;
}
if (line.toLowerCase().startsWith("content-disposition: form-data;")) {
key = (/name=([^;]+)/.exec(line) || [])[1].replace(/^["']|["']$/g, "") ?? "";
if (!key) throw new __wooksjs_event_http.HttpError(400, `Could not read multipart name: ${line}`);
if (key.length > MAX_KEY_LENGTH) throw new __wooksjs_event_http.HttpError(413, "Field name too long");
if ([
"__proto__",
"constructor",
"prototype"
].includes(key)) throw new __wooksjs_event_http.HttpError(400, `Illegal key name "${key}"`);
continue;
}
if (line.toLowerCase().startsWith("content-type:")) {
partContentType = (/content-type:\s?([^;]+)/i.exec(line) || [])[1] ?? "";
continue;
}
}
}
parsePart();
return result;
function parsePart() {
if (key && partContentType.includes("application/json") && typeof result[key] === "string") result[key] = safeJsonParse(result[key]);
}
}
function urlEncodedParser(v) {
return new __wooksjs_event_http.WooksURLSearchParams(v.trim()).toJson();
}
return {
isJson,
isHtml,
isXml,
isText,
isBinary,
isFormData,
isUrlencoded,
parseBody,
rawBody
};
}
//#endregion
exports.useBody = useBody;