@reckona/mreact-router 0.0.205 → 0.0.206
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/multipart.d.ts.map +1 -1
- package/dist/multipart.js +47 -25
- package/dist/multipart.js.map +1 -1
- package/package.json +11 -11
- package/src/multipart.ts +56 -26
package/dist/multipart.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IAClD,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IACpC,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,0BAA0B,CAAC;CACzE;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IACtD,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IAClD,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IACpC,iBAAiB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,0BAA0B,CAAC;CACzE;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IACtD,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAaD,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AACzD,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,2BAAgC,GACxC,aAAa,CAAC,mBAAmB,CAAC,CAQpC;AA+TD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASlE"}
|
package/dist/multipart.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const crlf = "\r\n";
|
|
2
2
|
const headerSeparator = "\r\n\r\n";
|
|
3
3
|
const maxHeaderBytes = 64 * 1024;
|
|
4
|
+
const maxMultipartBoundaryCharacters = 70;
|
|
4
5
|
export const defaultMultipartMaxBytes = 10 * 1024 * 1024;
|
|
5
6
|
export const defaultMultipartMaxParts = 1_000;
|
|
6
7
|
/**
|
|
@@ -35,6 +36,8 @@ async function parseMultipartRequest(request, options, queue) {
|
|
|
35
36
|
let totalBytes = 0;
|
|
36
37
|
let totalParts = 0;
|
|
37
38
|
let started = false;
|
|
39
|
+
let invalidOpeningBoundarySeen = false;
|
|
40
|
+
let firstBoundarySearchOffset = 0;
|
|
38
41
|
let currentPart;
|
|
39
42
|
queue.setCancel(() => {
|
|
40
43
|
void currentPart?.writer.abort(new Error("Multipart stream iteration was cancelled."));
|
|
@@ -50,26 +53,39 @@ async function parseMultipartRequest(request, options, queue) {
|
|
|
50
53
|
}
|
|
51
54
|
while (true) {
|
|
52
55
|
if (!started) {
|
|
53
|
-
const firstBoundaryIndex = indexOfBytes(buffer, firstBoundary);
|
|
56
|
+
const firstBoundaryIndex = indexOfBytes(buffer, firstBoundary, firstBoundarySearchOffset);
|
|
54
57
|
if (firstBoundaryIndex < 0) {
|
|
55
58
|
if (next.done) {
|
|
59
|
+
if (invalidOpeningBoundarySeen) {
|
|
60
|
+
throw new Error("Malformed multipart opening boundary.");
|
|
61
|
+
}
|
|
56
62
|
throw new Error("Multipart request body does not contain the opening boundary.");
|
|
57
63
|
}
|
|
58
64
|
trimBufferToTail(0);
|
|
65
|
+
firstBoundarySearchOffset = 0;
|
|
59
66
|
break;
|
|
60
67
|
}
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
queue.close();
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (!startsWithBytes(buffer, lineSuffix)) {
|
|
68
|
+
const firstBoundaryEnd = firstBoundaryIndex + firstBoundary.length;
|
|
69
|
+
if (buffer.length < firstBoundaryEnd + closeSuffix.length) {
|
|
67
70
|
if (next.done) {
|
|
68
71
|
throw new Error("Malformed multipart opening boundary.");
|
|
69
72
|
}
|
|
73
|
+
if (firstBoundaryIndex > 0) {
|
|
74
|
+
buffer = buffer.slice(firstBoundaryIndex);
|
|
75
|
+
}
|
|
76
|
+
firstBoundarySearchOffset = 0;
|
|
70
77
|
break;
|
|
71
78
|
}
|
|
72
|
-
buffer
|
|
79
|
+
if (startsWithBytes(buffer, closeSuffix, firstBoundaryEnd)) {
|
|
80
|
+
queue.close();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (!startsWithBytes(buffer, lineSuffix, firstBoundaryEnd)) {
|
|
84
|
+
invalidOpeningBoundarySeen = true;
|
|
85
|
+
firstBoundarySearchOffset = firstBoundaryIndex + 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
buffer = buffer.slice(firstBoundaryEnd + lineSuffix.length);
|
|
73
89
|
started = true;
|
|
74
90
|
}
|
|
75
91
|
if (currentPart === undefined) {
|
|
@@ -102,21 +118,25 @@ async function parseMultipartRequest(request, options, queue) {
|
|
|
102
118
|
continue;
|
|
103
119
|
}
|
|
104
120
|
await writePartChunk(currentPart, buffer.slice(0, delimiterIndex));
|
|
121
|
+
buffer = buffer.slice(delimiterIndex);
|
|
122
|
+
if (buffer.length < delimiter.length + closeSuffix.length) {
|
|
123
|
+
if (next.done) {
|
|
124
|
+
throw new Error("Malformed multipart boundary delimiter.");
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
const closesMultipart = startsWithBytes(buffer, closeSuffix, delimiter.length);
|
|
129
|
+
if (!closesMultipart && !startsWithBytes(buffer, lineSuffix, delimiter.length)) {
|
|
130
|
+
throw new Error("Malformed multipart boundary delimiter.");
|
|
131
|
+
}
|
|
105
132
|
await currentPart.writer.close();
|
|
106
|
-
buffer = buffer.slice(delimiterIndex + delimiter.length);
|
|
107
133
|
currentPart = undefined;
|
|
108
|
-
|
|
134
|
+
buffer = buffer.slice(delimiter.length + closeSuffix.length);
|
|
135
|
+
if (closesMultipart) {
|
|
109
136
|
queue.close();
|
|
110
137
|
return;
|
|
111
138
|
}
|
|
112
|
-
|
|
113
|
-
buffer = buffer.slice(lineSuffix.length);
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (next.done) {
|
|
117
|
-
throw new Error("Malformed multipart boundary delimiter.");
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
139
|
+
continue;
|
|
120
140
|
}
|
|
121
141
|
if (next.done) {
|
|
122
142
|
break;
|
|
@@ -255,7 +275,9 @@ function parseMultipartBoundary(contentType) {
|
|
|
255
275
|
const unquoted = value.startsWith("\"") && value.endsWith("\"")
|
|
256
276
|
? value.slice(1, -1)
|
|
257
277
|
: value;
|
|
258
|
-
return unquoted === ""
|
|
278
|
+
return unquoted === "" || unquoted.length > maxMultipartBoundaryCharacters
|
|
279
|
+
? undefined
|
|
280
|
+
: unquoted;
|
|
259
281
|
}
|
|
260
282
|
return undefined;
|
|
261
283
|
}
|
|
@@ -318,12 +340,12 @@ function concatBytes(left, right) {
|
|
|
318
340
|
function indexOfAscii(bytes, needle) {
|
|
319
341
|
return indexOfBytes(bytes, encodeAscii(needle));
|
|
320
342
|
}
|
|
321
|
-
function indexOfBytes(bytes, needle) {
|
|
322
|
-
if (needle.length === 0 || bytes.length < needle.length) {
|
|
343
|
+
function indexOfBytes(bytes, needle, startOffset = 0) {
|
|
344
|
+
if (needle.length === 0 || bytes.length - startOffset < needle.length) {
|
|
323
345
|
return -1;
|
|
324
346
|
}
|
|
325
347
|
const first = needle[0];
|
|
326
|
-
for (let index =
|
|
348
|
+
for (let index = startOffset; index <= bytes.length - needle.length; index += 1) {
|
|
327
349
|
if (bytes[index] !== first) {
|
|
328
350
|
continue;
|
|
329
351
|
}
|
|
@@ -340,12 +362,12 @@ function indexOfBytes(bytes, needle) {
|
|
|
340
362
|
}
|
|
341
363
|
return -1;
|
|
342
364
|
}
|
|
343
|
-
function startsWithBytes(bytes, prefix) {
|
|
344
|
-
if (bytes.length < prefix.length) {
|
|
365
|
+
function startsWithBytes(bytes, prefix, offset = 0) {
|
|
366
|
+
if (bytes.length - offset < prefix.length) {
|
|
345
367
|
return false;
|
|
346
368
|
}
|
|
347
369
|
for (let index = 0; index < prefix.length; index += 1) {
|
|
348
|
-
if (bytes[index] !== prefix[index]) {
|
|
370
|
+
if (bytes[offset + index] !== prefix[index]) {
|
|
349
371
|
return false;
|
|
350
372
|
}
|
|
351
373
|
}
|
package/dist/multipart.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multipart.js","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Configures multipart stream parsing limits and field handling.\n */\nexport interface MultipartStreamParseOptions {\n fields?: Readonly<Record<string, MultipartStreamFieldOptions>>;\n maxParts?: number;\n maxBytes?: number;\n}\n\n/**\n * Configures parsing behavior for a named multipart field.\n */\nexport interface MultipartStreamFieldOptions {\n type?: \"stream\" | \"text\";\n maxBytes?: number;\n}\n\n/**\n * Represents one parsed multipart field or file part.\n */\nexport interface MultipartStreamPart {\n name: string;\n filename?: string;\n safeFilename?: string;\n contentType?: string;\n headers: Headers;\n body: ReadableStream<Uint8Array<ArrayBufferLike>>;\n text(): Promise<string>;\n arrayBuffer(): Promise<ArrayBuffer>;\n fixedLengthStream(length?: number | bigint): MultipartFixedLengthStream;\n}\n\n/**\n * Couples a readable multipart part stream with a completion signal.\n */\nexport interface MultipartFixedLengthStream {\n readable: ReadableStream<Uint8Array<ArrayBufferLike>>;\n done: Promise<void>;\n}\n\ninterface PartWriter {\n name: string;\n maxBytes: number | undefined;\n bytes: number;\n writer: WritableStreamDefaultWriter<Uint8Array<ArrayBufferLike>>;\n}\n\nconst crlf = \"\\r\\n\";\nconst headerSeparator = \"\\r\\n\\r\\n\";\nconst maxHeaderBytes = 64 * 1024;\nexport const defaultMultipartMaxBytes = 10 * 1024 * 1024;\nexport const defaultMultipartMaxParts = 1_000;\n\n/**\n * Parses a multipart request body as an async iterable of streamable parts.\n */\nexport function parseMultipartStream(\n request: Request,\n options: MultipartStreamParseOptions = {},\n): AsyncIterable<MultipartStreamPart> {\n return {\n [Symbol.asyncIterator]() {\n const queue = new AsyncQueue<MultipartStreamPart>();\n void parseMultipartRequest(request, options, queue);\n return queue;\n },\n };\n}\n\nasync function parseMultipartRequest(\n request: Request,\n options: MultipartStreamParseOptions,\n queue: AsyncQueue<MultipartStreamPart>,\n): Promise<void> {\n const boundary = parseMultipartBoundary(request.headers.get(\"content-type\"));\n\n if (boundary === undefined) {\n queue.fail(new Error(\"Multipart request content-type must include a boundary.\"));\n return;\n }\n\n if (request.body === null) {\n queue.fail(new Error(\"Multipart request body is not readable.\"));\n return;\n }\n\n const reader = request.body.getReader();\n const delimiter = encodeAscii(`${crlf}--${boundary}`);\n const firstBoundary = encodeAscii(`--${boundary}`);\n const closeSuffix = encodeAscii(\"--\");\n const lineSuffix = encodeAscii(crlf);\n const keepTailBytes = delimiter.length + 4;\n let buffer: Uint8Array<ArrayBufferLike> = new Uint8Array();\n let totalBytes = 0;\n let totalParts = 0;\n let started = false;\n let currentPart: PartWriter | undefined;\n\n queue.setCancel(() => {\n void currentPart?.writer.abort(new Error(\"Multipart stream iteration was cancelled.\"));\n void reader.cancel();\n });\n\n try {\n while (true) {\n const next = await reader.read();\n\n if (!next.done) {\n totalBytes += next.value.byteLength;\n enforceByteLimit(\"multipart request\", totalBytes, options.maxBytes ?? defaultMultipartMaxBytes);\n buffer = concatBytes(buffer, next.value);\n }\n\n while (true) {\n if (!started) {\n const firstBoundaryIndex = indexOfBytes(buffer, firstBoundary);\n\n if (firstBoundaryIndex < 0) {\n if (next.done) {\n throw new Error(\"Multipart request body does not contain the opening boundary.\");\n }\n\n trimBufferToTail(0);\n break;\n }\n\n buffer = buffer.slice(firstBoundaryIndex + firstBoundary.length);\n\n if (startsWithBytes(buffer, closeSuffix)) {\n queue.close();\n return;\n }\n\n if (!startsWithBytes(buffer, lineSuffix)) {\n if (next.done) {\n throw new Error(\"Malformed multipart opening boundary.\");\n }\n break;\n }\n\n buffer = buffer.slice(lineSuffix.length);\n started = true;\n }\n\n if (currentPart === undefined) {\n const headerEnd = indexOfAscii(buffer, headerSeparator);\n\n if (headerEnd < 0) {\n if (next.done) {\n throw new Error(\"Multipart part ended before headers completed.\");\n }\n\n if (buffer.length > maxHeaderBytes) {\n throw new Error(`Multipart part headers exceeded ${maxHeaderBytes} bytes.`);\n }\n break;\n }\n\n totalParts += 1;\n enforcePartLimit(totalParts, options.maxParts ?? defaultMultipartMaxParts);\n currentPart = createPartWriter(\n decodeAscii(buffer.slice(0, headerEnd)),\n options,\n queue,\n );\n buffer = buffer.slice(headerEnd + headerSeparator.length);\n }\n\n const delimiterIndex = indexOfBytes(buffer, delimiter);\n\n if (delimiterIndex < 0) {\n if (next.done) {\n throw new Error(`Multipart part \"${currentPart.name}\" ended before the closing boundary.`);\n }\n\n const writableLength = Math.max(0, buffer.length - keepTailBytes);\n\n if (writableLength === 0) {\n break;\n }\n\n await writePartChunk(currentPart, buffer.slice(0, writableLength));\n buffer = buffer.slice(writableLength);\n continue;\n }\n\n await writePartChunk(currentPart, buffer.slice(0, delimiterIndex));\n await currentPart.writer.close();\n buffer = buffer.slice(delimiterIndex + delimiter.length);\n currentPart = undefined;\n\n if (startsWithBytes(buffer, closeSuffix)) {\n queue.close();\n return;\n }\n\n if (startsWithBytes(buffer, lineSuffix)) {\n buffer = buffer.slice(lineSuffix.length);\n continue;\n }\n\n if (next.done) {\n throw new Error(\"Malformed multipart boundary delimiter.\");\n }\n\n break;\n }\n\n if (next.done) {\n break;\n }\n }\n\n queue.close();\n } catch (error) {\n await currentPart?.writer.abort(error);\n queue.fail(error);\n } finally {\n queue.setCancel(undefined);\n reader.releaseLock();\n }\n\n function trimBufferToTail(prefixLength: number): void {\n if (buffer.length <= keepTailBytes + prefixLength) {\n return;\n }\n\n buffer = buffer.slice(buffer.length - keepTailBytes - prefixLength);\n }\n}\n\nfunction createPartWriter(\n rawHeaders: string,\n options: MultipartStreamParseOptions,\n queue: AsyncQueue<MultipartStreamPart>,\n): PartWriter {\n const headers = parsePartHeaders(rawHeaders);\n const disposition = parseContentDisposition(headers.get(\"content-disposition\"));\n\n if (disposition.name === undefined) {\n throw new Error(\"Multipart part is missing a form-data name.\");\n }\n\n const stream = new TransformStream<Uint8Array, Uint8Array>();\n const part = createPart({\n name: disposition.name,\n filename: disposition.filename,\n headers,\n body: stream.readable,\n });\n\n queue.push(part);\n\n return {\n name: disposition.name,\n maxBytes: options.fields?.[disposition.name]?.maxBytes,\n bytes: 0,\n writer: stream.writable.getWriter(),\n };\n}\n\nfunction createPart(options: {\n name: string;\n filename: string | undefined;\n headers: Headers;\n body: ReadableStream<Uint8Array>;\n}): MultipartStreamPart {\n const part: MultipartStreamPart = {\n name: options.name,\n headers: options.headers,\n body: options.body,\n text() {\n return new Response(options.body).text();\n },\n arrayBuffer() {\n return new Response(options.body).arrayBuffer();\n },\n fixedLengthStream(length) {\n const expectedLength = length ?? contentLengthFromHeaders(options.headers);\n const stream = createFixedLengthStream(expectedLength);\n\n return {\n readable: stream.readable,\n done: options.body.pipeTo(stream.writable),\n };\n },\n };\n\n if (options.filename !== undefined) {\n part.filename = options.filename;\n part.safeFilename = sanitizeMultipartFilename(options.filename);\n }\n\n const contentType = options.headers.get(\"content-type\");\n\n if (contentType !== null) {\n part.contentType = contentType;\n }\n\n return part;\n}\n\nfunction contentLengthFromHeaders(headers: Headers): number | bigint {\n const raw = headers.get(\"content-length\");\n\n if (raw === null || raw.trim() === \"\") {\n throw new Error(\n \"Multipart part fixedLengthStream() requires a byte length. Pass an explicit length or include a Content-Length part header.\",\n );\n }\n\n const parsed = Number(raw);\n\n if (!Number.isSafeInteger(parsed) || parsed < 0) {\n throw new Error(`Multipart part Content-Length must be a non-negative safe integer. Received ${JSON.stringify(raw)}.`);\n }\n\n return parsed;\n}\n\nfunction createFixedLengthStream(length: number | bigint): TransformStream<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>> {\n const FixedLengthStream = (globalThis as {\n FixedLengthStream?: new (\n length: number | bigint,\n ) => TransformStream<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>;\n }).FixedLengthStream;\n\n if (FixedLengthStream === undefined) {\n throw new Error(\n \"FixedLengthStream is not available in this runtime. Use arrayBuffer() or pass the part body to a destination that accepts unknown-length streams.\",\n );\n }\n\n return new FixedLengthStream(length);\n}\n\nasync function writePartChunk(\n part: PartWriter,\n chunk: Uint8Array<ArrayBufferLike>,\n): Promise<void> {\n if (chunk.byteLength === 0) {\n return;\n }\n\n part.bytes += chunk.byteLength;\n enforceByteLimit(`multipart field \"${part.name}\"`, part.bytes, part.maxBytes);\n await part.writer.write(chunk);\n}\n\nfunction enforceByteLimit(label: string, bytes: number, maxBytes: number | undefined): void {\n if (maxBytes !== undefined && bytes > maxBytes) {\n throw new Error(`${label} exceeded ${maxBytes} bytes.`);\n }\n}\n\nfunction enforcePartLimit(parts: number, maxParts: number | undefined): void {\n if (maxParts !== undefined && parts > maxParts) {\n throw new Error(`multipart request exceeded ${maxParts} parts.`);\n }\n}\n\nexport function sanitizeMultipartFilename(filename: string): string {\n const leaf = filename.split(/[\\\\/]/u).at(-1) ?? \"\";\n let sanitized = \"\";\n\n for (const char of leaf) {\n sanitized += isControlCharacter(char) ? \"_\" : char;\n }\n\n return sanitized === \"\" || sanitized === \".\" || sanitized === \"..\" ? \"upload.bin\" : sanitized;\n}\n\nfunction isControlCharacter(char: string): boolean {\n const code = char.charCodeAt(0);\n\n return code < 0x20 || code === 0x7f;\n}\n\nfunction parseMultipartBoundary(contentType: string | null): string | undefined {\n if (contentType === null) {\n return undefined;\n }\n\n const [mediaType, ...parameters] = contentType.split(\";\").map((part) => part.trim());\n\n if (mediaType?.toLowerCase() !== \"multipart/form-data\") {\n return undefined;\n }\n\n for (const parameter of parameters) {\n const [rawName, ...rawValue] = parameter.split(\"=\");\n\n if (rawName?.trim().toLowerCase() !== \"boundary\") {\n continue;\n }\n\n const value = rawValue.join(\"=\").trim();\n const unquoted = value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")\n ? value.slice(1, -1)\n : value;\n\n return unquoted === \"\" ? undefined : unquoted;\n }\n\n return undefined;\n}\n\nfunction parsePartHeaders(rawHeaders: string): Headers {\n const headers = new Headers();\n\n for (const line of rawHeaders.split(crlf)) {\n if (line.trim() === \"\") {\n continue;\n }\n\n const separator = line.indexOf(\":\");\n\n if (separator < 0) {\n throw new Error(`Malformed multipart header: ${line}`);\n }\n\n headers.append(\n line.slice(0, separator).trim().toLowerCase(),\n line.slice(separator + 1).trim(),\n );\n }\n\n return headers;\n}\n\nfunction parseContentDisposition(value: string | null): {\n name: string | undefined;\n filename: string | undefined;\n} {\n if (value === null) {\n return { name: undefined, filename: undefined };\n }\n\n const parameters = value.split(\";\").map((part) => part.trim());\n const disposition = parameters.shift()?.toLowerCase();\n\n if (disposition !== \"form-data\") {\n return { name: undefined, filename: undefined };\n }\n\n let name: string | undefined;\n let filename: string | undefined;\n\n for (const parameter of parameters) {\n const separator = parameter.indexOf(\"=\");\n\n if (separator < 0) {\n continue;\n }\n\n const key = parameter.slice(0, separator).trim().toLowerCase();\n const value = unquoteHeaderParameter(parameter.slice(separator + 1).trim());\n\n if (key === \"name\") {\n name = value;\n } else if (key === \"filename\") {\n filename = value;\n }\n }\n\n return { name, filename };\n}\n\nfunction unquoteHeaderParameter(value: string): string {\n if (!value.startsWith(\"\\\"\") || !value.endsWith(\"\\\"\")) {\n return value;\n }\n\n return value.slice(1, -1).replaceAll(/\\\\\"/g, \"\\\"\").replaceAll(/\\\\\\\\/g, \"\\\\\");\n}\n\nfunction concatBytes(\n left: Uint8Array<ArrayBufferLike>,\n right: Uint8Array<ArrayBufferLike>,\n): Uint8Array<ArrayBufferLike> {\n if (left.length === 0) {\n return right;\n }\n\n const next = new Uint8Array(left.length + right.length);\n next.set(left);\n next.set(right, left.length);\n return next;\n}\n\nfunction indexOfAscii(bytes: Uint8Array<ArrayBufferLike>, needle: string): number {\n return indexOfBytes(bytes, encodeAscii(needle));\n}\n\nfunction indexOfBytes(\n bytes: Uint8Array<ArrayBufferLike>,\n needle: Uint8Array<ArrayBufferLike>,\n): number {\n if (needle.length === 0 || bytes.length < needle.length) {\n return -1;\n }\n\n const first = needle[0];\n\n for (let index = 0; index <= bytes.length - needle.length; index += 1) {\n if (bytes[index] !== first) {\n continue;\n }\n\n let matched = true;\n\n for (let offset = 1; offset < needle.length; offset += 1) {\n if (bytes[index + offset] !== needle[offset]) {\n matched = false;\n break;\n }\n }\n\n if (matched) {\n return index;\n }\n }\n\n return -1;\n}\n\nfunction startsWithBytes(\n bytes: Uint8Array<ArrayBufferLike>,\n prefix: Uint8Array<ArrayBufferLike>,\n): boolean {\n if (bytes.length < prefix.length) {\n return false;\n }\n\n for (let index = 0; index < prefix.length; index += 1) {\n if (bytes[index] !== prefix[index]) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction encodeAscii(value: string): Uint8Array<ArrayBufferLike> {\n return new TextEncoder().encode(value);\n}\n\nfunction decodeAscii(value: Uint8Array<ArrayBufferLike>): string {\n return new TextDecoder(\"utf-8\", { fatal: false }).decode(value);\n}\n\nclass AsyncQueue<T> implements AsyncIterator<T> {\n private readonly values: T[] = [];\n private readonly waits: Array<{\n resolve(result: IteratorResult<T>): void;\n reject(error: unknown): void;\n }> = [];\n private done = false;\n private error: unknown;\n private onCancel: (() => void) | undefined;\n\n setCancel(onCancel: (() => void) | undefined): void {\n this.onCancel = onCancel;\n }\n\n push(value: T): void {\n const wait = this.waits.shift();\n\n if (wait !== undefined) {\n wait.resolve({ done: false, value });\n return;\n }\n\n this.values.push(value);\n }\n\n close(): void {\n this.done = true;\n\n for (const wait of this.waits.splice(0)) {\n wait.resolve({ done: true, value: undefined });\n }\n }\n\n fail(error: unknown): void {\n this.error = error;\n this.done = true;\n\n for (const wait of this.waits.splice(0)) {\n wait.reject(error);\n }\n }\n\n next(): Promise<IteratorResult<T>> {\n if (this.values.length > 0) {\n return Promise.resolve({ done: false, value: this.values.shift() as T });\n }\n\n if (this.error !== undefined) {\n return Promise.reject(this.error);\n }\n\n if (this.done) {\n return Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n this.waits.push({ resolve, reject });\n });\n }\n\n return(): Promise<IteratorResult<T>> {\n this.done = true;\n this.values.splice(0);\n this.onCancel?.();\n\n for (const wait of this.waits.splice(0)) {\n wait.resolve({ done: true, value: undefined });\n }\n\n return Promise.resolve({ done: true, value: undefined });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"multipart.js","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Configures multipart stream parsing limits and field handling.\n */\nexport interface MultipartStreamParseOptions {\n fields?: Readonly<Record<string, MultipartStreamFieldOptions>>;\n maxParts?: number;\n maxBytes?: number;\n}\n\n/**\n * Configures parsing behavior for a named multipart field.\n */\nexport interface MultipartStreamFieldOptions {\n type?: \"stream\" | \"text\";\n maxBytes?: number;\n}\n\n/**\n * Represents one parsed multipart field or file part.\n */\nexport interface MultipartStreamPart {\n name: string;\n filename?: string;\n safeFilename?: string;\n contentType?: string;\n headers: Headers;\n body: ReadableStream<Uint8Array<ArrayBufferLike>>;\n text(): Promise<string>;\n arrayBuffer(): Promise<ArrayBuffer>;\n fixedLengthStream(length?: number | bigint): MultipartFixedLengthStream;\n}\n\n/**\n * Couples a readable multipart part stream with a completion signal.\n */\nexport interface MultipartFixedLengthStream {\n readable: ReadableStream<Uint8Array<ArrayBufferLike>>;\n done: Promise<void>;\n}\n\ninterface PartWriter {\n name: string;\n maxBytes: number | undefined;\n bytes: number;\n writer: WritableStreamDefaultWriter<Uint8Array<ArrayBufferLike>>;\n}\n\nconst crlf = \"\\r\\n\";\nconst headerSeparator = \"\\r\\n\\r\\n\";\nconst maxHeaderBytes = 64 * 1024;\nconst maxMultipartBoundaryCharacters = 70;\nexport const defaultMultipartMaxBytes = 10 * 1024 * 1024;\nexport const defaultMultipartMaxParts = 1_000;\n\n/**\n * Parses a multipart request body as an async iterable of streamable parts.\n */\nexport function parseMultipartStream(\n request: Request,\n options: MultipartStreamParseOptions = {},\n): AsyncIterable<MultipartStreamPart> {\n return {\n [Symbol.asyncIterator]() {\n const queue = new AsyncQueue<MultipartStreamPart>();\n void parseMultipartRequest(request, options, queue);\n return queue;\n },\n };\n}\n\nasync function parseMultipartRequest(\n request: Request,\n options: MultipartStreamParseOptions,\n queue: AsyncQueue<MultipartStreamPart>,\n): Promise<void> {\n const boundary = parseMultipartBoundary(request.headers.get(\"content-type\"));\n\n if (boundary === undefined) {\n queue.fail(new Error(\"Multipart request content-type must include a boundary.\"));\n return;\n }\n\n if (request.body === null) {\n queue.fail(new Error(\"Multipart request body is not readable.\"));\n return;\n }\n\n const reader = request.body.getReader();\n const delimiter = encodeAscii(`${crlf}--${boundary}`);\n const firstBoundary = encodeAscii(`--${boundary}`);\n const closeSuffix = encodeAscii(\"--\");\n const lineSuffix = encodeAscii(crlf);\n const keepTailBytes = delimiter.length + 4;\n let buffer: Uint8Array<ArrayBufferLike> = new Uint8Array();\n let totalBytes = 0;\n let totalParts = 0;\n let started = false;\n let invalidOpeningBoundarySeen = false;\n let firstBoundarySearchOffset = 0;\n let currentPart: PartWriter | undefined;\n\n queue.setCancel(() => {\n void currentPart?.writer.abort(new Error(\"Multipart stream iteration was cancelled.\"));\n void reader.cancel();\n });\n\n try {\n while (true) {\n const next = await reader.read();\n\n if (!next.done) {\n totalBytes += next.value.byteLength;\n enforceByteLimit(\"multipart request\", totalBytes, options.maxBytes ?? defaultMultipartMaxBytes);\n buffer = concatBytes(buffer, next.value);\n }\n\n while (true) {\n if (!started) {\n const firstBoundaryIndex = indexOfBytes(buffer, firstBoundary, firstBoundarySearchOffset);\n\n if (firstBoundaryIndex < 0) {\n if (next.done) {\n if (invalidOpeningBoundarySeen) {\n throw new Error(\"Malformed multipart opening boundary.\");\n }\n\n throw new Error(\"Multipart request body does not contain the opening boundary.\");\n }\n\n trimBufferToTail(0);\n firstBoundarySearchOffset = 0;\n break;\n }\n\n const firstBoundaryEnd = firstBoundaryIndex + firstBoundary.length;\n\n if (buffer.length < firstBoundaryEnd + closeSuffix.length) {\n if (next.done) {\n throw new Error(\"Malformed multipart opening boundary.\");\n }\n\n if (firstBoundaryIndex > 0) {\n buffer = buffer.slice(firstBoundaryIndex);\n }\n firstBoundarySearchOffset = 0;\n break;\n }\n\n if (startsWithBytes(buffer, closeSuffix, firstBoundaryEnd)) {\n queue.close();\n return;\n }\n\n if (!startsWithBytes(buffer, lineSuffix, firstBoundaryEnd)) {\n invalidOpeningBoundarySeen = true;\n firstBoundarySearchOffset = firstBoundaryIndex + 1;\n continue;\n }\n\n buffer = buffer.slice(firstBoundaryEnd + lineSuffix.length);\n started = true;\n }\n\n if (currentPart === undefined) {\n const headerEnd = indexOfAscii(buffer, headerSeparator);\n\n if (headerEnd < 0) {\n if (next.done) {\n throw new Error(\"Multipart part ended before headers completed.\");\n }\n\n if (buffer.length > maxHeaderBytes) {\n throw new Error(`Multipart part headers exceeded ${maxHeaderBytes} bytes.`);\n }\n break;\n }\n\n totalParts += 1;\n enforcePartLimit(totalParts, options.maxParts ?? defaultMultipartMaxParts);\n currentPart = createPartWriter(\n decodeAscii(buffer.slice(0, headerEnd)),\n options,\n queue,\n );\n buffer = buffer.slice(headerEnd + headerSeparator.length);\n }\n\n const delimiterIndex = indexOfBytes(buffer, delimiter);\n\n if (delimiterIndex < 0) {\n if (next.done) {\n throw new Error(`Multipart part \"${currentPart.name}\" ended before the closing boundary.`);\n }\n\n const writableLength = Math.max(0, buffer.length - keepTailBytes);\n\n if (writableLength === 0) {\n break;\n }\n\n await writePartChunk(currentPart, buffer.slice(0, writableLength));\n buffer = buffer.slice(writableLength);\n continue;\n }\n\n await writePartChunk(currentPart, buffer.slice(0, delimiterIndex));\n buffer = buffer.slice(delimiterIndex);\n\n if (buffer.length < delimiter.length + closeSuffix.length) {\n if (next.done) {\n throw new Error(\"Malformed multipart boundary delimiter.\");\n }\n\n break;\n }\n\n const closesMultipart = startsWithBytes(buffer, closeSuffix, delimiter.length);\n\n if (!closesMultipart && !startsWithBytes(buffer, lineSuffix, delimiter.length)) {\n throw new Error(\"Malformed multipart boundary delimiter.\");\n }\n\n await currentPart.writer.close();\n currentPart = undefined;\n buffer = buffer.slice(delimiter.length + closeSuffix.length);\n\n if (closesMultipart) {\n queue.close();\n return;\n }\n\n continue;\n }\n\n if (next.done) {\n break;\n }\n }\n\n queue.close();\n } catch (error) {\n await currentPart?.writer.abort(error);\n queue.fail(error);\n } finally {\n queue.setCancel(undefined);\n reader.releaseLock();\n }\n\n function trimBufferToTail(prefixLength: number): void {\n if (buffer.length <= keepTailBytes + prefixLength) {\n return;\n }\n\n buffer = buffer.slice(buffer.length - keepTailBytes - prefixLength);\n }\n}\n\nfunction createPartWriter(\n rawHeaders: string,\n options: MultipartStreamParseOptions,\n queue: AsyncQueue<MultipartStreamPart>,\n): PartWriter {\n const headers = parsePartHeaders(rawHeaders);\n const disposition = parseContentDisposition(headers.get(\"content-disposition\"));\n\n if (disposition.name === undefined) {\n throw new Error(\"Multipart part is missing a form-data name.\");\n }\n\n const stream = new TransformStream<Uint8Array, Uint8Array>();\n const part = createPart({\n name: disposition.name,\n filename: disposition.filename,\n headers,\n body: stream.readable,\n });\n\n queue.push(part);\n\n return {\n name: disposition.name,\n maxBytes: options.fields?.[disposition.name]?.maxBytes,\n bytes: 0,\n writer: stream.writable.getWriter(),\n };\n}\n\nfunction createPart(options: {\n name: string;\n filename: string | undefined;\n headers: Headers;\n body: ReadableStream<Uint8Array>;\n}): MultipartStreamPart {\n const part: MultipartStreamPart = {\n name: options.name,\n headers: options.headers,\n body: options.body,\n text() {\n return new Response(options.body).text();\n },\n arrayBuffer() {\n return new Response(options.body).arrayBuffer();\n },\n fixedLengthStream(length) {\n const expectedLength = length ?? contentLengthFromHeaders(options.headers);\n const stream = createFixedLengthStream(expectedLength);\n\n return {\n readable: stream.readable,\n done: options.body.pipeTo(stream.writable),\n };\n },\n };\n\n if (options.filename !== undefined) {\n part.filename = options.filename;\n part.safeFilename = sanitizeMultipartFilename(options.filename);\n }\n\n const contentType = options.headers.get(\"content-type\");\n\n if (contentType !== null) {\n part.contentType = contentType;\n }\n\n return part;\n}\n\nfunction contentLengthFromHeaders(headers: Headers): number | bigint {\n const raw = headers.get(\"content-length\");\n\n if (raw === null || raw.trim() === \"\") {\n throw new Error(\n \"Multipart part fixedLengthStream() requires a byte length. Pass an explicit length or include a Content-Length part header.\",\n );\n }\n\n const parsed = Number(raw);\n\n if (!Number.isSafeInteger(parsed) || parsed < 0) {\n throw new Error(`Multipart part Content-Length must be a non-negative safe integer. Received ${JSON.stringify(raw)}.`);\n }\n\n return parsed;\n}\n\nfunction createFixedLengthStream(length: number | bigint): TransformStream<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>> {\n const FixedLengthStream = (globalThis as {\n FixedLengthStream?: new (\n length: number | bigint,\n ) => TransformStream<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>;\n }).FixedLengthStream;\n\n if (FixedLengthStream === undefined) {\n throw new Error(\n \"FixedLengthStream is not available in this runtime. Use arrayBuffer() or pass the part body to a destination that accepts unknown-length streams.\",\n );\n }\n\n return new FixedLengthStream(length);\n}\n\nasync function writePartChunk(\n part: PartWriter,\n chunk: Uint8Array<ArrayBufferLike>,\n): Promise<void> {\n if (chunk.byteLength === 0) {\n return;\n }\n\n part.bytes += chunk.byteLength;\n enforceByteLimit(`multipart field \"${part.name}\"`, part.bytes, part.maxBytes);\n await part.writer.write(chunk);\n}\n\nfunction enforceByteLimit(label: string, bytes: number, maxBytes: number | undefined): void {\n if (maxBytes !== undefined && bytes > maxBytes) {\n throw new Error(`${label} exceeded ${maxBytes} bytes.`);\n }\n}\n\nfunction enforcePartLimit(parts: number, maxParts: number | undefined): void {\n if (maxParts !== undefined && parts > maxParts) {\n throw new Error(`multipart request exceeded ${maxParts} parts.`);\n }\n}\n\nexport function sanitizeMultipartFilename(filename: string): string {\n const leaf = filename.split(/[\\\\/]/u).at(-1) ?? \"\";\n let sanitized = \"\";\n\n for (const char of leaf) {\n sanitized += isControlCharacter(char) ? \"_\" : char;\n }\n\n return sanitized === \"\" || sanitized === \".\" || sanitized === \"..\" ? \"upload.bin\" : sanitized;\n}\n\nfunction isControlCharacter(char: string): boolean {\n const code = char.charCodeAt(0);\n\n return code < 0x20 || code === 0x7f;\n}\n\nfunction parseMultipartBoundary(contentType: string | null): string | undefined {\n if (contentType === null) {\n return undefined;\n }\n\n const [mediaType, ...parameters] = contentType.split(\";\").map((part) => part.trim());\n\n if (mediaType?.toLowerCase() !== \"multipart/form-data\") {\n return undefined;\n }\n\n for (const parameter of parameters) {\n const [rawName, ...rawValue] = parameter.split(\"=\");\n\n if (rawName?.trim().toLowerCase() !== \"boundary\") {\n continue;\n }\n\n const value = rawValue.join(\"=\").trim();\n const unquoted = value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")\n ? value.slice(1, -1)\n : value;\n\n return unquoted === \"\" || unquoted.length > maxMultipartBoundaryCharacters\n ? undefined\n : unquoted;\n }\n\n return undefined;\n}\n\nfunction parsePartHeaders(rawHeaders: string): Headers {\n const headers = new Headers();\n\n for (const line of rawHeaders.split(crlf)) {\n if (line.trim() === \"\") {\n continue;\n }\n\n const separator = line.indexOf(\":\");\n\n if (separator < 0) {\n throw new Error(`Malformed multipart header: ${line}`);\n }\n\n headers.append(\n line.slice(0, separator).trim().toLowerCase(),\n line.slice(separator + 1).trim(),\n );\n }\n\n return headers;\n}\n\nfunction parseContentDisposition(value: string | null): {\n name: string | undefined;\n filename: string | undefined;\n} {\n if (value === null) {\n return { name: undefined, filename: undefined };\n }\n\n const parameters = value.split(\";\").map((part) => part.trim());\n const disposition = parameters.shift()?.toLowerCase();\n\n if (disposition !== \"form-data\") {\n return { name: undefined, filename: undefined };\n }\n\n let name: string | undefined;\n let filename: string | undefined;\n\n for (const parameter of parameters) {\n const separator = parameter.indexOf(\"=\");\n\n if (separator < 0) {\n continue;\n }\n\n const key = parameter.slice(0, separator).trim().toLowerCase();\n const value = unquoteHeaderParameter(parameter.slice(separator + 1).trim());\n\n if (key === \"name\") {\n name = value;\n } else if (key === \"filename\") {\n filename = value;\n }\n }\n\n return { name, filename };\n}\n\nfunction unquoteHeaderParameter(value: string): string {\n if (!value.startsWith(\"\\\"\") || !value.endsWith(\"\\\"\")) {\n return value;\n }\n\n return value.slice(1, -1).replaceAll(/\\\\\"/g, \"\\\"\").replaceAll(/\\\\\\\\/g, \"\\\\\");\n}\n\nfunction concatBytes(\n left: Uint8Array<ArrayBufferLike>,\n right: Uint8Array<ArrayBufferLike>,\n): Uint8Array<ArrayBufferLike> {\n if (left.length === 0) {\n return right;\n }\n\n const next = new Uint8Array(left.length + right.length);\n next.set(left);\n next.set(right, left.length);\n return next;\n}\n\nfunction indexOfAscii(bytes: Uint8Array<ArrayBufferLike>, needle: string): number {\n return indexOfBytes(bytes, encodeAscii(needle));\n}\n\nfunction indexOfBytes(\n bytes: Uint8Array<ArrayBufferLike>,\n needle: Uint8Array<ArrayBufferLike>,\n startOffset = 0,\n): number {\n if (needle.length === 0 || bytes.length - startOffset < needle.length) {\n return -1;\n }\n\n const first = needle[0];\n\n for (let index = startOffset; index <= bytes.length - needle.length; index += 1) {\n if (bytes[index] !== first) {\n continue;\n }\n\n let matched = true;\n\n for (let offset = 1; offset < needle.length; offset += 1) {\n if (bytes[index + offset] !== needle[offset]) {\n matched = false;\n break;\n }\n }\n\n if (matched) {\n return index;\n }\n }\n\n return -1;\n}\n\nfunction startsWithBytes(\n bytes: Uint8Array<ArrayBufferLike>,\n prefix: Uint8Array<ArrayBufferLike>,\n offset = 0,\n): boolean {\n if (bytes.length - offset < prefix.length) {\n return false;\n }\n\n for (let index = 0; index < prefix.length; index += 1) {\n if (bytes[offset + index] !== prefix[index]) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction encodeAscii(value: string): Uint8Array<ArrayBufferLike> {\n return new TextEncoder().encode(value);\n}\n\nfunction decodeAscii(value: Uint8Array<ArrayBufferLike>): string {\n return new TextDecoder(\"utf-8\", { fatal: false }).decode(value);\n}\n\nclass AsyncQueue<T> implements AsyncIterator<T> {\n private readonly values: T[] = [];\n private readonly waits: Array<{\n resolve(result: IteratorResult<T>): void;\n reject(error: unknown): void;\n }> = [];\n private done = false;\n private error: unknown;\n private onCancel: (() => void) | undefined;\n\n setCancel(onCancel: (() => void) | undefined): void {\n this.onCancel = onCancel;\n }\n\n push(value: T): void {\n const wait = this.waits.shift();\n\n if (wait !== undefined) {\n wait.resolve({ done: false, value });\n return;\n }\n\n this.values.push(value);\n }\n\n close(): void {\n this.done = true;\n\n for (const wait of this.waits.splice(0)) {\n wait.resolve({ done: true, value: undefined });\n }\n }\n\n fail(error: unknown): void {\n this.error = error;\n this.done = true;\n\n for (const wait of this.waits.splice(0)) {\n wait.reject(error);\n }\n }\n\n next(): Promise<IteratorResult<T>> {\n if (this.values.length > 0) {\n return Promise.resolve({ done: false, value: this.values.shift() as T });\n }\n\n if (this.error !== undefined) {\n return Promise.reject(this.error);\n }\n\n if (this.done) {\n return Promise.resolve({ done: true, value: undefined });\n }\n\n return new Promise((resolve, reject) => {\n this.waits.push({ resolve, reject });\n });\n }\n\n return(): Promise<IteratorResult<T>> {\n this.done = true;\n this.values.splice(0);\n this.onCancel?.();\n\n for (const wait of this.waits.splice(0)) {\n wait.resolve({ done: true, value: undefined });\n }\n\n return Promise.resolve({ done: true, value: undefined });\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-router",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.206",
|
|
4
4
|
"description": "File-system app router, SSR, actions, and deployment adapters for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jsx",
|
|
@@ -111,20 +111,20 @@
|
|
|
111
111
|
"dependencies": {
|
|
112
112
|
"@typescript/typescript6": "^6.0.2",
|
|
113
113
|
"esbuild": ">=0.28.1 <0.29",
|
|
114
|
-
"@reckona/mreact": "0.0.
|
|
115
|
-
"@reckona/mreact-compat": "0.0.
|
|
116
|
-
"@reckona/mreact-
|
|
117
|
-
"@reckona/mreact-
|
|
118
|
-
"@reckona/mreact-
|
|
119
|
-
"@reckona/mreact-
|
|
120
|
-
"@reckona/mreact-reactive-dom": "0.0.
|
|
121
|
-
"@reckona/mreact-
|
|
122
|
-
"@reckona/mreact-
|
|
114
|
+
"@reckona/mreact": "0.0.206",
|
|
115
|
+
"@reckona/mreact-compat": "0.0.206",
|
|
116
|
+
"@reckona/mreact-compiler": "0.0.206",
|
|
117
|
+
"@reckona/mreact-query": "0.0.206",
|
|
118
|
+
"@reckona/mreact-reactive-core": "0.0.206",
|
|
119
|
+
"@reckona/mreact-devtools": "0.0.206",
|
|
120
|
+
"@reckona/mreact-reactive-dom": "0.0.206",
|
|
121
|
+
"@reckona/mreact-shared": "0.0.206",
|
|
122
|
+
"@reckona/mreact-server": "0.0.206"
|
|
123
123
|
},
|
|
124
124
|
"peerDependencies": {
|
|
125
125
|
"vite": ">=8.1.4 <9"
|
|
126
126
|
},
|
|
127
127
|
"optionalDependencies": {
|
|
128
|
-
"@reckona/mreact-router-native": "0.0.
|
|
128
|
+
"@reckona/mreact-router-native": "0.0.206"
|
|
129
129
|
}
|
|
130
130
|
}
|
package/src/multipart.ts
CHANGED
|
@@ -48,6 +48,7 @@ interface PartWriter {
|
|
|
48
48
|
const crlf = "\r\n";
|
|
49
49
|
const headerSeparator = "\r\n\r\n";
|
|
50
50
|
const maxHeaderBytes = 64 * 1024;
|
|
51
|
+
const maxMultipartBoundaryCharacters = 70;
|
|
51
52
|
export const defaultMultipartMaxBytes = 10 * 1024 * 1024;
|
|
52
53
|
export const defaultMultipartMaxParts = 1_000;
|
|
53
54
|
|
|
@@ -94,6 +95,8 @@ async function parseMultipartRequest(
|
|
|
94
95
|
let totalBytes = 0;
|
|
95
96
|
let totalParts = 0;
|
|
96
97
|
let started = false;
|
|
98
|
+
let invalidOpeningBoundarySeen = false;
|
|
99
|
+
let firstBoundarySearchOffset = 0;
|
|
97
100
|
let currentPart: PartWriter | undefined;
|
|
98
101
|
|
|
99
102
|
queue.setCancel(() => {
|
|
@@ -113,32 +116,48 @@ async function parseMultipartRequest(
|
|
|
113
116
|
|
|
114
117
|
while (true) {
|
|
115
118
|
if (!started) {
|
|
116
|
-
const firstBoundaryIndex = indexOfBytes(buffer, firstBoundary);
|
|
119
|
+
const firstBoundaryIndex = indexOfBytes(buffer, firstBoundary, firstBoundarySearchOffset);
|
|
117
120
|
|
|
118
121
|
if (firstBoundaryIndex < 0) {
|
|
119
122
|
if (next.done) {
|
|
123
|
+
if (invalidOpeningBoundarySeen) {
|
|
124
|
+
throw new Error("Malformed multipart opening boundary.");
|
|
125
|
+
}
|
|
126
|
+
|
|
120
127
|
throw new Error("Multipart request body does not contain the opening boundary.");
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
trimBufferToTail(0);
|
|
131
|
+
firstBoundarySearchOffset = 0;
|
|
124
132
|
break;
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (startsWithBytes(buffer, closeSuffix)) {
|
|
130
|
-
queue.close();
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
135
|
+
const firstBoundaryEnd = firstBoundaryIndex + firstBoundary.length;
|
|
133
136
|
|
|
134
|
-
if (
|
|
137
|
+
if (buffer.length < firstBoundaryEnd + closeSuffix.length) {
|
|
135
138
|
if (next.done) {
|
|
136
139
|
throw new Error("Malformed multipart opening boundary.");
|
|
137
140
|
}
|
|
141
|
+
|
|
142
|
+
if (firstBoundaryIndex > 0) {
|
|
143
|
+
buffer = buffer.slice(firstBoundaryIndex);
|
|
144
|
+
}
|
|
145
|
+
firstBoundarySearchOffset = 0;
|
|
138
146
|
break;
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
buffer
|
|
149
|
+
if (startsWithBytes(buffer, closeSuffix, firstBoundaryEnd)) {
|
|
150
|
+
queue.close();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!startsWithBytes(buffer, lineSuffix, firstBoundaryEnd)) {
|
|
155
|
+
invalidOpeningBoundarySeen = true;
|
|
156
|
+
firstBoundarySearchOffset = firstBoundaryIndex + 1;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
buffer = buffer.slice(firstBoundaryEnd + lineSuffix.length);
|
|
142
161
|
started = true;
|
|
143
162
|
}
|
|
144
163
|
|
|
@@ -185,25 +204,32 @@ async function parseMultipartRequest(
|
|
|
185
204
|
}
|
|
186
205
|
|
|
187
206
|
await writePartChunk(currentPart, buffer.slice(0, delimiterIndex));
|
|
188
|
-
|
|
189
|
-
buffer = buffer.slice(delimiterIndex + delimiter.length);
|
|
190
|
-
currentPart = undefined;
|
|
207
|
+
buffer = buffer.slice(delimiterIndex);
|
|
191
208
|
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
209
|
+
if (buffer.length < delimiter.length + closeSuffix.length) {
|
|
210
|
+
if (next.done) {
|
|
211
|
+
throw new Error("Malformed multipart boundary delimiter.");
|
|
212
|
+
}
|
|
196
213
|
|
|
197
|
-
|
|
198
|
-
buffer = buffer.slice(lineSuffix.length);
|
|
199
|
-
continue;
|
|
214
|
+
break;
|
|
200
215
|
}
|
|
201
216
|
|
|
202
|
-
|
|
217
|
+
const closesMultipart = startsWithBytes(buffer, closeSuffix, delimiter.length);
|
|
218
|
+
|
|
219
|
+
if (!closesMultipart && !startsWithBytes(buffer, lineSuffix, delimiter.length)) {
|
|
203
220
|
throw new Error("Malformed multipart boundary delimiter.");
|
|
204
221
|
}
|
|
205
222
|
|
|
206
|
-
|
|
223
|
+
await currentPart.writer.close();
|
|
224
|
+
currentPart = undefined;
|
|
225
|
+
buffer = buffer.slice(delimiter.length + closeSuffix.length);
|
|
226
|
+
|
|
227
|
+
if (closesMultipart) {
|
|
228
|
+
queue.close();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
continue;
|
|
207
233
|
}
|
|
208
234
|
|
|
209
235
|
if (next.done) {
|
|
@@ -399,7 +425,9 @@ function parseMultipartBoundary(contentType: string | null): string | undefined
|
|
|
399
425
|
? value.slice(1, -1)
|
|
400
426
|
: value;
|
|
401
427
|
|
|
402
|
-
return unquoted === ""
|
|
428
|
+
return unquoted === "" || unquoted.length > maxMultipartBoundaryCharacters
|
|
429
|
+
? undefined
|
|
430
|
+
: unquoted;
|
|
403
431
|
}
|
|
404
432
|
|
|
405
433
|
return undefined;
|
|
@@ -495,14 +523,15 @@ function indexOfAscii(bytes: Uint8Array<ArrayBufferLike>, needle: string): numbe
|
|
|
495
523
|
function indexOfBytes(
|
|
496
524
|
bytes: Uint8Array<ArrayBufferLike>,
|
|
497
525
|
needle: Uint8Array<ArrayBufferLike>,
|
|
526
|
+
startOffset = 0,
|
|
498
527
|
): number {
|
|
499
|
-
if (needle.length === 0 || bytes.length < needle.length) {
|
|
528
|
+
if (needle.length === 0 || bytes.length - startOffset < needle.length) {
|
|
500
529
|
return -1;
|
|
501
530
|
}
|
|
502
531
|
|
|
503
532
|
const first = needle[0];
|
|
504
533
|
|
|
505
|
-
for (let index =
|
|
534
|
+
for (let index = startOffset; index <= bytes.length - needle.length; index += 1) {
|
|
506
535
|
if (bytes[index] !== first) {
|
|
507
536
|
continue;
|
|
508
537
|
}
|
|
@@ -527,13 +556,14 @@ function indexOfBytes(
|
|
|
527
556
|
function startsWithBytes(
|
|
528
557
|
bytes: Uint8Array<ArrayBufferLike>,
|
|
529
558
|
prefix: Uint8Array<ArrayBufferLike>,
|
|
559
|
+
offset = 0,
|
|
530
560
|
): boolean {
|
|
531
|
-
if (bytes.length < prefix.length) {
|
|
561
|
+
if (bytes.length - offset < prefix.length) {
|
|
532
562
|
return false;
|
|
533
563
|
}
|
|
534
564
|
|
|
535
565
|
for (let index = 0; index < prefix.length; index += 1) {
|
|
536
|
-
if (bytes[index] !== prefix[index]) {
|
|
566
|
+
if (bytes[offset + index] !== prefix[index]) {
|
|
537
567
|
return false;
|
|
538
568
|
}
|
|
539
569
|
}
|