summaryrefslogtreecommitdiff
path: root/ext/fetch/21_formdata.js
diff options
context:
space:
mode:
authorLeo Kettmeir <crowlkats@toaxl.com>2023-02-07 20:22:46 +0100
committerGitHub <noreply@github.com>2023-02-07 20:22:46 +0100
commitb4aa1530970f7b9cc4e6f2f27e077852c4e178d3 (patch)
tree3d008912affe8550692183bd2697a386db5e3c79 /ext/fetch/21_formdata.js
parent65500f36e870b4ada3996b06aa287e30177d21a3 (diff)
refactor: Use ES modules for internal runtime code (#17648)
This PR refactors all internal js files (except core) to be written as ES modules. `__bootstrap`has been mostly replaced with static imports in form in `internal:[path to file from repo root]`. To specify if files are ESM, an `esm` method has been added to `Extension`, similar to the `js` method. A new ModuleLoader called `InternalModuleLoader` has been added to enable the loading of internal specifiers, which is used in all situations except when a snapshot is only loaded, and not a new one is created from it. --------- Co-authored-by: Bartek IwaƄczuk <biwanczuk@gmail.com>
Diffstat (limited to 'ext/fetch/21_formdata.js')
-rw-r--r--ext/fetch/21_formdata.js888
1 files changed, 445 insertions, 443 deletions
diff --git a/ext/fetch/21_formdata.js b/ext/fetch/21_formdata.js
index d253976ef..1639646e0 100644
--- a/ext/fetch/21_formdata.js
+++ b/ext/fetch/21_formdata.js
@@ -8,516 +8,518 @@
/// <reference path="../web/06_streams_types.d.ts" />
/// <reference path="./lib.deno_fetch.d.ts" />
/// <reference lib="esnext" />
-"use strict";
-
-((window) => {
- const core = window.Deno.core;
- const webidl = globalThis.__bootstrap.webidl;
- const { Blob, BlobPrototype, File, FilePrototype } =
- globalThis.__bootstrap.file;
- const {
- ArrayPrototypePush,
- ArrayPrototypeSlice,
- ArrayPrototypeSplice,
- Map,
- MapPrototypeGet,
- MapPrototypeSet,
- MathRandom,
- ObjectPrototypeIsPrototypeOf,
- Symbol,
- StringFromCharCode,
- StringPrototypeTrim,
- StringPrototypeSlice,
- StringPrototypeSplit,
- StringPrototypeReplace,
- StringPrototypeIndexOf,
- StringPrototypePadStart,
- StringPrototypeCodePointAt,
- StringPrototypeReplaceAll,
- TypeError,
- TypedArrayPrototypeSubarray,
- } = window.__bootstrap.primordials;
-
- const entryList = Symbol("entry list");
- /**
- * @param {string} name
- * @param {string | Blob} value
- * @param {string | undefined} filename
- * @returns {FormDataEntry}
- */
- function createEntry(name, value, filename) {
- if (
- ObjectPrototypeIsPrototypeOf(BlobPrototype, value) &&
- !ObjectPrototypeIsPrototypeOf(FilePrototype, value)
- ) {
- value = new File([value], "blob", { type: value.type });
- }
- if (
- ObjectPrototypeIsPrototypeOf(FilePrototype, value) &&
- filename !== undefined
- ) {
- value = new File([value], filename, {
- type: value.type,
- lastModified: value.lastModified,
- });
+const core = globalThis.Deno.core;
+import * as webidl from "internal:ext/webidl/00_webidl.js";
+import {
+ Blob,
+ BlobPrototype,
+ File,
+ FilePrototype,
+} from "internal:ext/web/09_file.js";
+const primordials = globalThis.__bootstrap.primordials;
+const {
+ ArrayPrototypePush,
+ ArrayPrototypeSlice,
+ ArrayPrototypeSplice,
+ Map,
+ MapPrototypeGet,
+ MapPrototypeSet,
+ MathRandom,
+ ObjectPrototypeIsPrototypeOf,
+ Symbol,
+ StringFromCharCode,
+ StringPrototypeTrim,
+ StringPrototypeSlice,
+ StringPrototypeSplit,
+ StringPrototypeReplace,
+ StringPrototypeIndexOf,
+ StringPrototypePadStart,
+ StringPrototypeCodePointAt,
+ StringPrototypeReplaceAll,
+ TypeError,
+ TypedArrayPrototypeSubarray,
+} = primordials;
+
+const entryList = Symbol("entry list");
+
+/**
+ * @param {string} name
+ * @param {string | Blob} value
+ * @param {string | undefined} filename
+ * @returns {FormDataEntry}
+ */
+function createEntry(name, value, filename) {
+ if (
+ ObjectPrototypeIsPrototypeOf(BlobPrototype, value) &&
+ !ObjectPrototypeIsPrototypeOf(FilePrototype, value)
+ ) {
+ value = new File([value], "blob", { type: value.type });
+ }
+ if (
+ ObjectPrototypeIsPrototypeOf(FilePrototype, value) &&
+ filename !== undefined
+ ) {
+ value = new File([value], filename, {
+ type: value.type,
+ lastModified: value.lastModified,
+ });
+ }
+ return {
+ name,
+ // @ts-expect-error because TS is not smart enough
+ value,
+ };
+}
+
+/**
+ * @typedef FormDataEntry
+ * @property {string} name
+ * @property {FormDataEntryValue} value
+ */
+
+class FormData {
+ /** @type {FormDataEntry[]} */
+ [entryList] = [];
+
+ /** @param {void} form */
+ constructor(form) {
+ if (form !== undefined) {
+ webidl.illegalConstructor();
}
- return {
- name,
- // @ts-expect-error because TS is not smart enough
- value,
- };
+ this[webidl.brand] = webidl.brand;
}
/**
- * @typedef FormDataEntry
- * @property {string} name
- * @property {FormDataEntryValue} value
+ * @param {string} name
+ * @param {string | Blob} valueOrBlobValue
+ * @param {string} [filename]
+ * @returns {void}
*/
-
- class FormData {
- /** @type {FormDataEntry[]} */
- [entryList] = [];
-
- /** @param {void} form */
- constructor(form) {
- if (form !== undefined) {
- webidl.illegalConstructor();
- }
- this[webidl.brand] = webidl.brand;
- }
-
- /**
- * @param {string} name
- * @param {string | Blob} valueOrBlobValue
- * @param {string} [filename]
- * @returns {void}
- */
- append(name, valueOrBlobValue, filename) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'append' on 'FormData'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
-
- name = webidl.converters["USVString"](name, {
+ append(name, valueOrBlobValue, filename) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'append' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
+ valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
- valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
- prefix,
- context: "Argument 2",
- });
- if (filename !== undefined) {
- filename = webidl.converters["USVString"](filename, {
- prefix,
- context: "Argument 3",
- });
- }
- } else {
- valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
+ if (filename !== undefined) {
+ filename = webidl.converters["USVString"](filename, {
prefix,
- context: "Argument 2",
+ context: "Argument 3",
});
}
-
- const entry = createEntry(name, valueOrBlobValue, filename);
-
- ArrayPrototypePush(this[entryList], entry);
- }
-
- /**
- * @param {string} name
- * @returns {void}
- */
- delete(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'name' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
-
- name = webidl.converters["USVString"](name, {
+ } else {
+ valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
-
- const list = this[entryList];
- for (let i = 0; i < list.length; i++) {
- if (list[i].name === name) {
- ArrayPrototypeSplice(list, i, 1);
- i--;
- }
- }
}
- /**
- * @param {string} name
- * @returns {FormDataEntryValue | null}
- */
- get(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'get' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ const entry = createEntry(name, valueOrBlobValue, filename);
- name = webidl.converters["USVString"](name, {
- prefix,
- context: "Argument 1",
- });
+ ArrayPrototypePush(this[entryList], entry);
+ }
- const entries = this[entryList];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry.name === name) return entry.value;
+ /**
+ * @param {string} name
+ * @returns {void}
+ */
+ delete(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'name' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const list = this[entryList];
+ for (let i = 0; i < list.length; i++) {
+ if (list[i].name === name) {
+ ArrayPrototypeSplice(list, i, 1);
+ i--;
}
- return null;
}
+ }
- /**
- * @param {string} name
- * @returns {FormDataEntryValue[]}
- */
- getAll(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'getAll' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
-
- name = webidl.converters["USVString"](name, {
- prefix,
- context: "Argument 1",
- });
+ /**
+ * @param {string} name
+ * @returns {FormDataEntryValue | null}
+ */
+ get(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'get' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- const returnList = [];
- const entries = this[entryList];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry.name === name) ArrayPrototypePush(returnList, entry.value);
- }
- return returnList;
+ const entries = this[entryList];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry.name === name) return entry.value;
}
+ return null;
+ }
- /**
- * @param {string} name
- * @returns {boolean}
- */
- has(name) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'has' on 'FormData'";
- webidl.requiredArguments(arguments.length, 1, { prefix });
+ /**
+ * @param {string} name
+ * @returns {FormDataEntryValue[]}
+ */
+ getAll(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'getAll' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
- name = webidl.converters["USVString"](name, {
- prefix,
- context: "Argument 1",
- });
+ const returnList = [];
+ const entries = this[entryList];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry.name === name) ArrayPrototypePush(returnList, entry.value);
+ }
+ return returnList;
+ }
- const entries = this[entryList];
- for (let i = 0; i < entries.length; ++i) {
- const entry = entries[i];
- if (entry.name === name) return true;
- }
- return false;
+ /**
+ * @param {string} name
+ * @returns {boolean}
+ */
+ has(name) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'has' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const entries = this[entryList];
+ for (let i = 0; i < entries.length; ++i) {
+ const entry = entries[i];
+ if (entry.name === name) return true;
}
+ return false;
+ }
- /**
- * @param {string} name
- * @param {string | Blob} valueOrBlobValue
- * @param {string} [filename]
- * @returns {void}
- */
- set(name, valueOrBlobValue, filename) {
- webidl.assertBranded(this, FormDataPrototype);
- const prefix = "Failed to execute 'set' on 'FormData'";
- webidl.requiredArguments(arguments.length, 2, { prefix });
-
- name = webidl.converters["USVString"](name, {
+ /**
+ * @param {string} name
+ * @param {string | Blob} valueOrBlobValue
+ * @param {string} [filename]
+ * @returns {void}
+ */
+ set(name, valueOrBlobValue, filename) {
+ webidl.assertBranded(this, FormDataPrototype);
+ const prefix = "Failed to execute 'set' on 'FormData'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+
+ name = webidl.converters["USVString"](name, {
+ prefix,
+ context: "Argument 1",
+ });
+ if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
+ valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
prefix,
- context: "Argument 1",
+ context: "Argument 2",
});
- if (ObjectPrototypeIsPrototypeOf(BlobPrototype, valueOrBlobValue)) {
- valueOrBlobValue = webidl.converters["Blob"](valueOrBlobValue, {
- prefix,
- context: "Argument 2",
- });
- if (filename !== undefined) {
- filename = webidl.converters["USVString"](filename, {
- prefix,
- context: "Argument 3",
- });
- }
- } else {
- valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
+ if (filename !== undefined) {
+ filename = webidl.converters["USVString"](filename, {
prefix,
- context: "Argument 2",
+ context: "Argument 3",
});
}
+ } else {
+ valueOrBlobValue = webidl.converters["USVString"](valueOrBlobValue, {
+ prefix,
+ context: "Argument 2",
+ });
+ }
- const entry = createEntry(name, valueOrBlobValue, filename);
+ const entry = createEntry(name, valueOrBlobValue, filename);
- const list = this[entryList];
- let added = false;
- for (let i = 0; i < list.length; i++) {
- if (list[i].name === name) {
- if (!added) {
- list[i] = entry;
- added = true;
- } else {
- ArrayPrototypeSplice(list, i, 1);
- i--;
- }
+ const list = this[entryList];
+ let added = false;
+ for (let i = 0; i < list.length; i++) {
+ if (list[i].name === name) {
+ if (!added) {
+ list[i] = entry;
+ added = true;
+ } else {
+ ArrayPrototypeSplice(list, i, 1);
+ i--;
}
}
- if (!added) {
- ArrayPrototypePush(list, entry);
- }
+ }
+ if (!added) {
+ ArrayPrototypePush(list, entry);
}
}
+}
- webidl.mixinPairIterable("FormData", FormData, entryList, "name", "value");
+webidl.mixinPairIterable("FormData", FormData, entryList, "name", "value");
- webidl.configurePrototype(FormData);
- const FormDataPrototype = FormData.prototype;
+webidl.configurePrototype(FormData);
+const FormDataPrototype = FormData.prototype;
- const escape = (str, isFilename) => {
- const escapeMap = {
- "\n": "%0A",
- "\r": "%0D",
- '"': "%22",
- };
-
- return StringPrototypeReplace(
- isFilename ? str : StringPrototypeReplace(str, /\r?\n|\r/g, "\r\n"),
- /([\n\r"])/g,
- (c) => escapeMap[c],
- );
+const escape = (str, isFilename) => {
+ const escapeMap = {
+ "\n": "%0A",
+ "\r": "%0D",
+ '"': "%22",
};
- /**
- * convert FormData to a Blob synchronous without reading all of the files
- * @param {globalThis.FormData} formData
- */
- function formDataToBlob(formData) {
- const boundary = StringPrototypePadStart(
- StringPrototypeSlice(
- StringPrototypeReplaceAll(`${MathRandom()}${MathRandom()}`, ".", ""),
- -28,
- ),
- 32,
- "-",
- );
- const chunks = [];
- const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="`;
-
- // deno-lint-ignore prefer-primordials
- for (const { 0: name, 1: value } of formData) {
- if (typeof value === "string") {
- ArrayPrototypePush(
- chunks,
- prefix + escape(name) + '"' + CRLF + CRLF +
- StringPrototypeReplace(value, /\r(?!\n)|(?<!\r)\n/g, CRLF) + CRLF,
- );
- } else {
- ArrayPrototypePush(
- chunks,
- prefix + escape(name) + `"; filename="${escape(value.name, true)}"` +
- CRLF +
- `Content-Type: ${value.type || "application/octet-stream"}\r\n\r\n`,
- value,
- CRLF,
- );
- }
+ return StringPrototypeReplace(
+ isFilename ? str : StringPrototypeReplace(str, /\r?\n|\r/g, "\r\n"),
+ /([\n\r"])/g,
+ (c) => escapeMap[c],
+ );
+};
+
+/**
+ * convert FormData to a Blob synchronous without reading all of the files
+ * @param {globalThis.FormData} formData
+ */
+function formDataToBlob(formData) {
+ const boundary = StringPrototypePadStart(
+ StringPrototypeSlice(
+ StringPrototypeReplaceAll(`${MathRandom()}${MathRandom()}`, ".", ""),
+ -28,
+ ),
+ 32,
+ "-",
+ );
+ const chunks = [];
+ const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="`;
+
+ // deno-lint-ignore prefer-primordials
+ for (const { 0: name, 1: value } of formData) {
+ if (typeof value === "string") {
+ ArrayPrototypePush(
+ chunks,
+ prefix + escape(name) + '"' + CRLF + CRLF +
+ StringPrototypeReplace(value, /\r(?!\n)|(?<!\r)\n/g, CRLF) + CRLF,
+ );
+ } else {
+ ArrayPrototypePush(
+ chunks,
+ prefix + escape(name) + `"; filename="${escape(value.name, true)}"` +
+ CRLF +
+ `Content-Type: ${value.type || "application/octet-stream"}\r\n\r\n`,
+ value,
+ CRLF,
+ );
}
+ }
- ArrayPrototypePush(chunks, `--${boundary}--`);
-
- return new Blob(chunks, {
- type: "multipart/form-data; boundary=" + boundary,
- });
+ ArrayPrototypePush(chunks, `--${boundary}--`);
+
+ return new Blob(chunks, {
+ type: "multipart/form-data; boundary=" + boundary,
+ });
+}
+
+/**
+ * @param {string} value
+ * @returns {Map<string, string>}
+ */
+function parseContentDisposition(value) {
+ /** @type {Map<string, string>} */
+ const params = new Map();
+ // Forced to do so for some Map constructor param mismatch
+ const values = ArrayPrototypeSlice(StringPrototypeSplit(value, ";"), 1);
+ for (let i = 0; i < values.length; i++) {
+ const entries = StringPrototypeSplit(StringPrototypeTrim(values[i]), "=");
+ if (entries.length > 1) {
+ MapPrototypeSet(
+ params,
+ entries[0],
+ StringPrototypeReplace(entries[1], /^"([^"]*)"$/, "$1"),
+ );
+ }
}
+ return params;
+}
+const CRLF = "\r\n";
+const LF = StringPrototypeCodePointAt(CRLF, 1);
+const CR = StringPrototypeCodePointAt(CRLF, 0);
+
+class MultipartParser {
/**
- * @param {string} value
- * @returns {Map<string, string>}
+ * @param {Uint8Array} body
+ * @param {string | undefined} boundary
*/
- function parseContentDisposition(value) {
- /** @type {Map<string, string>} */
- const params = new Map();
- // Forced to do so for some Map constructor param mismatch
- const values = ArrayPrototypeSlice(StringPrototypeSplit(value, ";"), 1);
- for (let i = 0; i < values.length; i++) {
- const entries = StringPrototypeSplit(StringPrototypeTrim(values[i]), "=");
- if (entries.length > 1) {
- MapPrototypeSet(
- params,
- entries[0],
- StringPrototypeReplace(entries[1], /^"([^"]*)"$/, "$1"),
- );
- }
+ constructor(body, boundary) {
+ if (!boundary) {
+ throw new TypeError("multipart/form-data must provide a boundary");
}
- return params;
+
+ this.boundary = `--${boundary}`;
+ this.body = body;
+ this.boundaryChars = core.encode(this.boundary);
}
- const CRLF = "\r\n";
- const LF = StringPrototypeCodePointAt(CRLF, 1);
- const CR = StringPrototypeCodePointAt(CRLF, 0);
-
- class MultipartParser {
- /**
- * @param {Uint8Array} body
- * @param {string | undefined} boundary
- */
- constructor(body, boundary) {
- if (!boundary) {
- throw new TypeError("multipart/form-data must provide a boundary");
+ /**
+ * @param {string} headersText
+ * @returns {{ headers: Headers, disposition: Map<string, string> }}
+ */
+ #parseHeaders(headersText) {
+ const headers = new Headers();
+ const rawHeaders = StringPrototypeSplit(headersText, "\r\n");
+ for (let i = 0; i < rawHeaders.length; ++i) {
+ const rawHeader = rawHeaders[i];
+ const sepIndex = StringPrototypeIndexOf(rawHeader, ":");
+ if (sepIndex < 0) {
+ continue; // Skip this header
}
-
- this.boundary = `--${boundary}`;
- this.body = body;
- this.boundaryChars = core.encode(this.boundary);
+ const key = StringPrototypeSlice(rawHeader, 0, sepIndex);
+ const value = StringPrototypeSlice(rawHeader, sepIndex + 1);
+ headers.set(key, value);
}
- /**
- * @param {string} headersText
- * @returns {{ headers: Headers, disposition: Map<string, string> }}
- */
- #parseHeaders(headersText) {
- const headers = new Headers();
- const rawHeaders = StringPrototypeSplit(headersText, "\r\n");
- for (let i = 0; i < rawHeaders.length; ++i) {
- const rawHeader = rawHeaders[i];
- const sepIndex = StringPrototypeIndexOf(rawHeader, ":");
- if (sepIndex < 0) {
- continue; // Skip this header
- }
- const key = StringPrototypeSlice(rawHeader, 0, sepIndex);
- const value = StringPrototypeSlice(rawHeader, sepIndex + 1);
- headers.set(key, value);
- }
-
- const disposition = parseContentDisposition(
- headers.get("Content-Disposition") ?? "",
- );
+ const disposition = parseContentDisposition(
+ headers.get("Content-Disposition") ?? "",
+ );
- return { headers, disposition };
- }
+ return { headers, disposition };
+ }
- /**
- * @returns {FormData}
- */
- parse() {
- // To have fields body must be at least 2 boundaries + \r\n + --
- // on the last boundary.
- if (this.body.length < (this.boundary.length * 2) + 4) {
- const decodedBody = core.decode(this.body);
- const lastBoundary = this.boundary + "--";
- // check if it's an empty valid form data
- if (
- decodedBody === lastBoundary ||
- decodedBody === lastBoundary + "\r\n"
- ) {
- return new FormData();
- }
- throw new TypeError("Unable to parse body as form data.");
+ /**
+ * @returns {FormData}
+ */
+ parse() {
+ // To have fields body must be at least 2 boundaries + \r\n + --
+ // on the last boundary.
+ if (this.body.length < (this.boundary.length * 2) + 4) {
+ const decodedBody = core.decode(this.body);
+ const lastBoundary = this.boundary + "--";
+ // check if it's an empty valid form data
+ if (
+ decodedBody === lastBoundary ||
+ decodedBody === lastBoundary + "\r\n"
+ ) {
+ return new FormData();
}
+ throw new TypeError("Unable to parse body as form data.");
+ }
- const formData = new FormData();
- let headerText = "";
- let boundaryIndex = 0;
- let state = 0;
- let fileStart = 0;
+ const formData = new FormData();
+ let headerText = "";
+ let boundaryIndex = 0;
+ let state = 0;
+ let fileStart = 0;
- for (let i = 0; i < this.body.length; i++) {
- const byte = this.body[i];
- const prevByte = this.body[i - 1];
- const isNewLine = byte === LF && prevByte === CR;
+ for (let i = 0; i < this.body.length; i++) {
+ const byte = this.body[i];
+ const prevByte = this.body[i - 1];
+ const isNewLine = byte === LF && prevByte === CR;
- if (state === 1 || state === 2 || state == 3) {
- headerText += StringFromCharCode(byte);
- }
- if (state === 0 && isNewLine) {
- state = 1;
- } else if (state === 1 && isNewLine) {
- state = 2;
- const headersDone = this.body[i + 1] === CR &&
- this.body[i + 2] === LF;
-
- if (headersDone) {
- state = 3;
- }
- } else if (state === 2 && isNewLine) {
+ if (state === 1 || state === 2 || state == 3) {
+ headerText += StringFromCharCode(byte);
+ }
+ if (state === 0 && isNewLine) {
+ state = 1;
+ } else if (state === 1 && isNewLine) {
+ state = 2;
+ const headersDone = this.body[i + 1] === CR &&
+ this.body[i + 2] === LF;
+
+ if (headersDone) {
state = 3;
- } else if (state === 3 && isNewLine) {
- state = 4;
- fileStart = i + 1;
- } else if (state === 4) {
- if (this.boundaryChars[boundaryIndex] !== byte) {
- boundaryIndex = 0;
- } else {
- boundaryIndex++;
+ }
+ } else if (state === 2 && isNewLine) {
+ state = 3;
+ } else if (state === 3 && isNewLine) {
+ state = 4;
+ fileStart = i + 1;
+ } else if (state === 4) {
+ if (this.boundaryChars[boundaryIndex] !== byte) {
+ boundaryIndex = 0;
+ } else {
+ boundaryIndex++;
+ }
+
+ if (boundaryIndex >= this.boundary.length) {
+ const { headers, disposition } = this.#parseHeaders(headerText);
+ const content = TypedArrayPrototypeSubarray(
+ this.body,
+ fileStart,
+ i - boundaryIndex - 1,
+ );
+ // https://fetch.spec.whatwg.org/#ref-for-dom-body-formdata
+ const filename = MapPrototypeGet(disposition, "filename");
+ const name = MapPrototypeGet(disposition, "name");
+
+ state = 5;
+ // Reset
+ boundaryIndex = 0;
+ headerText = "";
+
+ if (!name) {
+ continue; // Skip, unknown name
}
- if (boundaryIndex >= this.boundary.length) {
- const { headers, disposition } = this.#parseHeaders(headerText);
- const content = TypedArrayPrototypeSubarray(
- this.body,
- fileStart,
- i - boundaryIndex - 1,
- );
- // https://fetch.spec.whatwg.org/#ref-for-dom-body-formdata
- const filename = MapPrototypeGet(disposition, "filename");
- const name = MapPrototypeGet(disposition, "name");
-
- state = 5;
- // Reset
- boundaryIndex = 0;
- headerText = "";
-
- if (!name) {
- continue; // Skip, unknown name
- }
-
- if (filename) {
- const blob = new Blob([content], {
- type: headers.get("Content-Type") || "application/octet-stream",
- });
- formData.append(name, blob, filename);
- } else {
- formData.append(name, core.decode(content));
- }
+ if (filename) {
+ const blob = new Blob([content], {
+ type: headers.get("Content-Type") || "application/octet-stream",
+ });
+ formData.append(name, blob, filename);
+ } else {
+ formData.append(name, core.decode(content));
}
- } else if (state === 5 && isNewLine) {
- state = 1;
}
+ } else if (state === 5 && isNewLine) {
+ state = 1;
}
-
- return formData;
}
- }
-
- /**
- * @param {Uint8Array} body
- * @param {string | undefined} boundary
- * @returns {FormData}
- */
- function parseFormData(body, boundary) {
- const parser = new MultipartParser(body, boundary);
- return parser.parse();
- }
- /**
- * @param {FormDataEntry[]} entries
- * @returns {FormData}
- */
- function formDataFromEntries(entries) {
- const fd = new FormData();
- fd[entryList] = entries;
- return fd;
+ return formData;
}
-
- webidl.converters["FormData"] = webidl
- .createInterfaceConverter("FormData", FormDataPrototype);
-
- globalThis.__bootstrap.formData = {
- FormData,
- FormDataPrototype,
- formDataToBlob,
- parseFormData,
- formDataFromEntries,
- };
-})(globalThis);
+}
+
+/**
+ * @param {Uint8Array} body
+ * @param {string | undefined} boundary
+ * @returns {FormData}
+ */
+function parseFormData(body, boundary) {
+ const parser = new MultipartParser(body, boundary);
+ return parser.parse();
+}
+
+/**
+ * @param {FormDataEntry[]} entries
+ * @returns {FormData}
+ */
+function formDataFromEntries(entries) {
+ const fd = new FormData();
+ fd[entryList] = entries;
+ return fd;
+}
+
+webidl.converters["FormData"] = webidl
+ .createInterfaceConverter("FormData", FormDataPrototype);
+
+export {
+ FormData,
+ formDataFromEntries,
+ FormDataPrototype,
+ formDataToBlob,
+ parseFormData,
+};