UNPKG

@wooksjs/http-body

Version:
149 lines (145 loc) 5.38 kB
//#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;