@remix-run/multipart-parser 0.14.0 → 0.14.1
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/lib/buffer-search.d.ts.map +1 -1
- package/dist/lib/buffer-search.js +4 -3
- package/dist/lib/multipart-request.d.ts +3 -3
- package/dist/lib/multipart-request.js +3 -3
- package/dist/lib/multipart.d.ts +3 -6
- package/dist/lib/multipart.d.ts.map +1 -1
- package/dist/lib/multipart.js +8 -10
- package/dist/lib/multipart.node.d.ts +4 -4
- package/dist/lib/multipart.node.js +4 -4
- package/package.json +6 -6
- package/src/lib/buffer-search.ts +6 -3
- package/src/lib/multipart-request.ts +3 -3
- package/src/lib/multipart.node.ts +4 -4
- package/src/lib/multipart.ts +8 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buffer-search.d.ts","sourceRoot":"","sources":["../../src/lib/buffer-search.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC/C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"buffer-search.d.ts","sourceRoot":"","sources":["../../src/lib/buffer-search.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC/C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAkC5D;AAED,MAAM,WAAW,yBAAyB;IACxC,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAAA;CAC/B;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,yBAAyB,CAyBlF"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export function createSearch(pattern) {
|
|
2
2
|
let needle = new TextEncoder().encode(pattern);
|
|
3
3
|
let search;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
// Use the built-in Buffer.indexOf method on Node.js for better perf.
|
|
5
|
+
let BufferClass = globalThis.Buffer;
|
|
6
|
+
if (BufferClass && !('Bun' in globalThis || 'Deno' in globalThis)) {
|
|
7
|
+
search = (haystack, start = 0) => BufferClass.prototype.indexOf.call(haystack, needle, start);
|
|
7
8
|
}
|
|
8
9
|
else {
|
|
9
10
|
let needleEnd = needle.length - 1;
|
|
@@ -3,14 +3,14 @@ import type { MultipartParserOptions, MultipartPart } from './multipart.ts';
|
|
|
3
3
|
* Extracts the boundary string from a `multipart/*` content type.
|
|
4
4
|
*
|
|
5
5
|
* @param contentType The `Content-Type` header value from the request
|
|
6
|
-
* @
|
|
6
|
+
* @returns The boundary string if found, or null if not present
|
|
7
7
|
*/
|
|
8
8
|
export declare function getMultipartBoundary(contentType: string): string | null;
|
|
9
9
|
/**
|
|
10
10
|
* Returns true if the given request contains multipart data.
|
|
11
11
|
*
|
|
12
12
|
* @param request The `Request` object to check
|
|
13
|
-
* @
|
|
13
|
+
* @returns `true` if the request is a multipart request, `false` otherwise
|
|
14
14
|
*/
|
|
15
15
|
export declare function isMultipartRequest(request: Request): boolean;
|
|
16
16
|
/**
|
|
@@ -19,7 +19,7 @@ export declare function isMultipartRequest(request: Request): boolean;
|
|
|
19
19
|
*
|
|
20
20
|
* @param request The `Request` object containing multipart data
|
|
21
21
|
* @param options Optional parser options, such as `maxHeaderSize` and `maxFileSize`
|
|
22
|
-
* @
|
|
22
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
23
23
|
*/
|
|
24
24
|
export declare function parseMultipartRequest(request: Request, options?: MultipartParserOptions): AsyncGenerator<MultipartPart, void, unknown>;
|
|
25
25
|
//# sourceMappingURL=multipart-request.d.ts.map
|
|
@@ -3,7 +3,7 @@ import { MultipartParseError, parseMultipartStream } from "./multipart.js";
|
|
|
3
3
|
* Extracts the boundary string from a `multipart/*` content type.
|
|
4
4
|
*
|
|
5
5
|
* @param contentType The `Content-Type` header value from the request
|
|
6
|
-
* @
|
|
6
|
+
* @returns The boundary string if found, or null if not present
|
|
7
7
|
*/
|
|
8
8
|
export function getMultipartBoundary(contentType) {
|
|
9
9
|
let match = /boundary=(?:"([^"]+)"|([^;]+))/i.exec(contentType);
|
|
@@ -13,7 +13,7 @@ export function getMultipartBoundary(contentType) {
|
|
|
13
13
|
* Returns true if the given request contains multipart data.
|
|
14
14
|
*
|
|
15
15
|
* @param request The `Request` object to check
|
|
16
|
-
* @
|
|
16
|
+
* @returns `true` if the request is a multipart request, `false` otherwise
|
|
17
17
|
*/
|
|
18
18
|
export function isMultipartRequest(request) {
|
|
19
19
|
let contentType = request.headers.get('Content-Type');
|
|
@@ -25,7 +25,7 @@ export function isMultipartRequest(request) {
|
|
|
25
25
|
*
|
|
26
26
|
* @param request The `Request` object containing multipart data
|
|
27
27
|
* @param options Optional parser options, such as `maxHeaderSize` and `maxFileSize`
|
|
28
|
-
* @
|
|
28
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
29
29
|
*/
|
|
30
30
|
export async function* parseMultipartRequest(request, options) {
|
|
31
31
|
if (!isMultipartRequest(request)) {
|
package/dist/lib/multipart.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Headers from '@remix-run/headers';
|
|
2
1
|
/**
|
|
3
2
|
* The base class for errors thrown by the multipart parser.
|
|
4
3
|
*/
|
|
@@ -58,7 +57,7 @@ export interface ParseMultipartOptions {
|
|
|
58
57
|
*
|
|
59
58
|
* @param message The multipart message as a `Uint8Array` or an iterable of `Uint8Array` chunks
|
|
60
59
|
* @param options Options for the parser
|
|
61
|
-
* @
|
|
60
|
+
* @returns A generator that yields `MultipartPart` objects
|
|
62
61
|
*/
|
|
63
62
|
export declare function parseMultipart(message: Uint8Array | Iterable<Uint8Array>, options: ParseMultipartOptions): Generator<MultipartPart, void, unknown>;
|
|
64
63
|
/**
|
|
@@ -69,7 +68,7 @@ export declare function parseMultipart(message: Uint8Array | Iterable<Uint8Array
|
|
|
69
68
|
*
|
|
70
69
|
* @param stream A stream containing multipart data as a `ReadableStream<Uint8Array>`
|
|
71
70
|
* @param options Options for the parser
|
|
72
|
-
* @
|
|
71
|
+
* @returns An async generator that yields `MultipartPart` objects
|
|
73
72
|
*/
|
|
74
73
|
export declare function parseMultipartStream(stream: ReadableStream<Uint8Array>, options: ParseMultipartOptions): AsyncGenerator<MultipartPart, void, unknown>;
|
|
75
74
|
/**
|
|
@@ -93,7 +92,7 @@ export declare class MultipartParser {
|
|
|
93
92
|
* Write a chunk of data to the parser.
|
|
94
93
|
*
|
|
95
94
|
* @param chunk A chunk of data to write to the parser
|
|
96
|
-
* @
|
|
95
|
+
* @returns A generator yielding `MultipartPart` objects as they are parsed
|
|
97
96
|
*/
|
|
98
97
|
write(chunk: Uint8Array): Generator<MultipartPart, void, unknown>;
|
|
99
98
|
/**
|
|
@@ -101,8 +100,6 @@ export declare class MultipartParser {
|
|
|
101
100
|
*
|
|
102
101
|
* Note: This will throw if the multipart message is incomplete or
|
|
103
102
|
* wasn't properly terminated.
|
|
104
|
-
*
|
|
105
|
-
* @return void
|
|
106
103
|
*/
|
|
107
104
|
finish(): void;
|
|
108
105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/lib/multipart.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/lib/multipart.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C;;OAEG;IACH,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,mBAAmB;IACjE;;OAEG;IACH,YAAY,aAAa,EAAE,MAAM,EAGhC;CACF;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,mBAAmB;IAC/D;;OAEG;IACH,YAAY,WAAW,EAAE,MAAM,EAG9B;CACF;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAiB,cAAc,CAC7B,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,EAC1C,OAAO,EAAE,qBAAqB,GAC7B,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAmBzC;AAED;;;;;;;;;GASG;AACH,wBAAuB,oBAAoB,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAe9C;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAA;AAa5E;;GAEG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAa5B;;;OAGG;IACH,YAAY,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,EAU7D;IAED;;;;;OAKG;IACF,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CA+GjE;IAWD;;;;;OAKG;IACH,MAAM,IAAI,IAAI,CAIb;CACF;AAID;;GAEG;AACH,qBAAa,aAAa;;IACxB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,CAAA;IAK9B;;;OAGG;IACH,YAAY,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,EAGpD;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,WAAW,CAE7B;IAED;;;OAGG;IACH,IAAI,KAAK,IAAI,UAAU,CAUtB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,OAAO,CAMrB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;OAEG;IACH,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAQjB;IAED;;;;;OAKG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|
package/dist/lib/multipart.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ContentDisposition, ContentType, parse as parseRawHeaders } from '@remix-run/headers';
|
|
2
2
|
import { createSearch, createPartialTailSearch, } from "./buffer-search.js";
|
|
3
3
|
import { readStream } from "./read-stream.js";
|
|
4
4
|
/**
|
|
@@ -45,7 +45,7 @@ export class MaxFileSizeExceededError extends MultipartParseError {
|
|
|
45
45
|
*
|
|
46
46
|
* @param message The multipart message as a `Uint8Array` or an iterable of `Uint8Array` chunks
|
|
47
47
|
* @param options Options for the parser
|
|
48
|
-
* @
|
|
48
|
+
* @returns A generator that yields `MultipartPart` objects
|
|
49
49
|
*/
|
|
50
50
|
export function* parseMultipart(message, options) {
|
|
51
51
|
let parser = new MultipartParser(options.boundary, {
|
|
@@ -73,7 +73,7 @@ export function* parseMultipart(message, options) {
|
|
|
73
73
|
*
|
|
74
74
|
* @param stream A stream containing multipart data as a `ReadableStream<Uint8Array>`
|
|
75
75
|
* @param options Options for the parser
|
|
76
|
-
* @
|
|
76
|
+
* @returns An async generator that yields `MultipartPart` objects
|
|
77
77
|
*/
|
|
78
78
|
export async function* parseMultipartStream(stream, options) {
|
|
79
79
|
let parser = new MultipartParser(options.boundary, {
|
|
@@ -130,7 +130,7 @@ export class MultipartParser {
|
|
|
130
130
|
* Write a chunk of data to the parser.
|
|
131
131
|
*
|
|
132
132
|
* @param chunk A chunk of data to write to the parser
|
|
133
|
-
* @
|
|
133
|
+
* @returns A generator yielding `MultipartPart` objects as they are parsed
|
|
134
134
|
*/
|
|
135
135
|
*write(chunk) {
|
|
136
136
|
if (this.#state === MultipartParserStateDone) {
|
|
@@ -229,8 +229,6 @@ export class MultipartParser {
|
|
|
229
229
|
*
|
|
230
230
|
* Note: This will throw if the multipart message is incomplete or
|
|
231
231
|
* wasn't properly terminated.
|
|
232
|
-
*
|
|
233
|
-
* @return void
|
|
234
232
|
*/
|
|
235
233
|
finish() {
|
|
236
234
|
if (this.#state !== MultipartParserStateDone) {
|
|
@@ -281,7 +279,7 @@ export class MultipartPart {
|
|
|
281
279
|
*/
|
|
282
280
|
get headers() {
|
|
283
281
|
if (!this.#headers) {
|
|
284
|
-
this.#headers =
|
|
282
|
+
this.#headers = parseRawHeaders(decoder.decode(this.#header));
|
|
285
283
|
}
|
|
286
284
|
return this.#headers;
|
|
287
285
|
}
|
|
@@ -301,19 +299,19 @@ export class MultipartPart {
|
|
|
301
299
|
* The filename of the part, if it is a file upload.
|
|
302
300
|
*/
|
|
303
301
|
get filename() {
|
|
304
|
-
return this.headers.
|
|
302
|
+
return ContentDisposition.from(this.headers.get('content-disposition')).preferredFilename;
|
|
305
303
|
}
|
|
306
304
|
/**
|
|
307
305
|
* The media type of the part.
|
|
308
306
|
*/
|
|
309
307
|
get mediaType() {
|
|
310
|
-
return this.headers.
|
|
308
|
+
return ContentType.from(this.headers.get('content-type')).mediaType;
|
|
311
309
|
}
|
|
312
310
|
/**
|
|
313
311
|
* The name of the part, usually the `name` of the field in the `<form>` that submitted the request.
|
|
314
312
|
*/
|
|
315
313
|
get name() {
|
|
316
|
-
return this.headers.
|
|
314
|
+
return ContentDisposition.from(this.headers.get('content-disposition')).name;
|
|
317
315
|
}
|
|
318
316
|
/**
|
|
319
317
|
* The size of the content in bytes.
|
|
@@ -9,7 +9,7 @@ import type { ParseMultipartOptions, MultipartParserOptions, MultipartPart } fro
|
|
|
9
9
|
*
|
|
10
10
|
* @param message The multipart message as a `Buffer` or an iterable of `Buffer` chunks
|
|
11
11
|
* @param options Options for the parser
|
|
12
|
-
* @
|
|
12
|
+
* @returns A generator yielding `MultipartPart` objects
|
|
13
13
|
*/
|
|
14
14
|
export declare function parseMultipart(message: Buffer | Iterable<Buffer>, options: ParseMultipartOptions): Generator<MultipartPart, void, unknown>;
|
|
15
15
|
/**
|
|
@@ -20,14 +20,14 @@ export declare function parseMultipart(message: Buffer | Iterable<Buffer>, optio
|
|
|
20
20
|
*
|
|
21
21
|
* @param stream A Node.js `Readable` stream containing multipart data
|
|
22
22
|
* @param options Options for the parser
|
|
23
|
-
* @
|
|
23
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
24
24
|
*/
|
|
25
25
|
export declare function parseMultipartStream(stream: Readable, options: ParseMultipartOptions): AsyncGenerator<MultipartPart, void, unknown>;
|
|
26
26
|
/**
|
|
27
27
|
* Returns true if the given request is a multipart request.
|
|
28
28
|
*
|
|
29
29
|
* @param req The Node.js `http.IncomingMessage` object to check
|
|
30
|
-
* @
|
|
30
|
+
* @returns `true` if the request is a multipart request, `false` otherwise
|
|
31
31
|
*/
|
|
32
32
|
export declare function isMultipartRequest(req: http.IncomingMessage): boolean;
|
|
33
33
|
/**
|
|
@@ -35,7 +35,7 @@ export declare function isMultipartRequest(req: http.IncomingMessage): boolean;
|
|
|
35
35
|
*
|
|
36
36
|
* @param req The Node.js `http.IncomingMessage` object containing multipart data
|
|
37
37
|
* @param options Options for the parser
|
|
38
|
-
* @
|
|
38
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
39
39
|
*/
|
|
40
40
|
export declare function parseMultipartRequest(req: http.IncomingMessage, options?: MultipartParserOptions): AsyncGenerator<MultipartPart, void, unknown>;
|
|
41
41
|
//# sourceMappingURL=multipart.node.d.ts.map
|
|
@@ -9,7 +9,7 @@ import { getMultipartBoundary } from "./multipart-request.js";
|
|
|
9
9
|
*
|
|
10
10
|
* @param message The multipart message as a `Buffer` or an iterable of `Buffer` chunks
|
|
11
11
|
* @param options Options for the parser
|
|
12
|
-
* @
|
|
12
|
+
* @returns A generator yielding `MultipartPart` objects
|
|
13
13
|
*/
|
|
14
14
|
export function* parseMultipart(message, options) {
|
|
15
15
|
yield* parseMultipartWeb(message, options);
|
|
@@ -22,7 +22,7 @@ export function* parseMultipart(message, options) {
|
|
|
22
22
|
*
|
|
23
23
|
* @param stream A Node.js `Readable` stream containing multipart data
|
|
24
24
|
* @param options Options for the parser
|
|
25
|
-
* @
|
|
25
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
26
26
|
*/
|
|
27
27
|
export async function* parseMultipartStream(stream, options) {
|
|
28
28
|
yield* parseMultipartStreamWeb(Readable.toWeb(stream), options);
|
|
@@ -31,7 +31,7 @@ export async function* parseMultipartStream(stream, options) {
|
|
|
31
31
|
* Returns true if the given request is a multipart request.
|
|
32
32
|
*
|
|
33
33
|
* @param req The Node.js `http.IncomingMessage` object to check
|
|
34
|
-
* @
|
|
34
|
+
* @returns `true` if the request is a multipart request, `false` otherwise
|
|
35
35
|
*/
|
|
36
36
|
export function isMultipartRequest(req) {
|
|
37
37
|
let contentType = req.headers['content-type'];
|
|
@@ -42,7 +42,7 @@ export function isMultipartRequest(req) {
|
|
|
42
42
|
*
|
|
43
43
|
* @param req The Node.js `http.IncomingMessage` object containing multipart data
|
|
44
44
|
* @param options Options for the parser
|
|
45
|
-
* @
|
|
45
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
46
46
|
*/
|
|
47
47
|
export async function* parseMultipartRequest(req, options) {
|
|
48
48
|
if (!isMultipartRequest(req)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/multipart-parser",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "A fast, efficient parser for multipart streams in any JavaScript environment",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"repository": {
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"./package.json": "./package.json"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@remix-run/headers": "^0.
|
|
33
|
+
"@remix-run/headers": "^0.19.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^24.6.0",
|
|
37
|
-
"typescript": "
|
|
37
|
+
"@typescript/native-preview": "7.0.0-dev.20251125.1"
|
|
38
38
|
},
|
|
39
39
|
"keywords": [
|
|
40
40
|
"multipart",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"bench:bun": "bun run ./bench/runner.ts",
|
|
48
48
|
"bench:deno": "deno run --allow-sys ./bench/runner.ts",
|
|
49
49
|
"bench:node": "node --disable-warning=ExperimentalWarning ./bench/runner.ts",
|
|
50
|
-
"build": "
|
|
50
|
+
"build": "tsgo -p tsconfig.build.json",
|
|
51
51
|
"clean": "git clean -fdX",
|
|
52
|
-
"test": "node --disable-warning=ExperimentalWarning --test
|
|
53
|
-
"typecheck": "
|
|
52
|
+
"test": "node --disable-warning=ExperimentalWarning --test",
|
|
53
|
+
"typecheck": "tsgo --noEmit"
|
|
54
54
|
}
|
|
55
55
|
}
|
package/src/lib/buffer-search.ts
CHANGED
|
@@ -6,9 +6,12 @@ export function createSearch(pattern: string): SearchFunction {
|
|
|
6
6
|
let needle = new TextEncoder().encode(pattern)
|
|
7
7
|
|
|
8
8
|
let search: SearchFunction
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
// Use the built-in Buffer.indexOf method on Node.js for better perf.
|
|
10
|
+
let BufferClass = (globalThis as any).Buffer as
|
|
11
|
+
| { prototype: { indexOf(this: Uint8Array, needle: Uint8Array, start: number): number } }
|
|
12
|
+
| undefined
|
|
13
|
+
if (BufferClass && !('Bun' in globalThis || 'Deno' in globalThis)) {
|
|
14
|
+
search = (haystack, start = 0) => BufferClass.prototype.indexOf.call(haystack, needle, start)
|
|
12
15
|
} else {
|
|
13
16
|
let needleEnd = needle.length - 1
|
|
14
17
|
let skipTable = new Uint8Array(256).fill(needle.length)
|
|
@@ -5,7 +5,7 @@ import { MultipartParseError, parseMultipartStream } from './multipart.ts'
|
|
|
5
5
|
* Extracts the boundary string from a `multipart/*` content type.
|
|
6
6
|
*
|
|
7
7
|
* @param contentType The `Content-Type` header value from the request
|
|
8
|
-
* @
|
|
8
|
+
* @returns The boundary string if found, or null if not present
|
|
9
9
|
*/
|
|
10
10
|
export function getMultipartBoundary(contentType: string): string | null {
|
|
11
11
|
let match = /boundary=(?:"([^"]+)"|([^;]+))/i.exec(contentType)
|
|
@@ -16,7 +16,7 @@ export function getMultipartBoundary(contentType: string): string | null {
|
|
|
16
16
|
* Returns true if the given request contains multipart data.
|
|
17
17
|
*
|
|
18
18
|
* @param request The `Request` object to check
|
|
19
|
-
* @
|
|
19
|
+
* @returns `true` if the request is a multipart request, `false` otherwise
|
|
20
20
|
*/
|
|
21
21
|
export function isMultipartRequest(request: Request): boolean {
|
|
22
22
|
let contentType = request.headers.get('Content-Type')
|
|
@@ -29,7 +29,7 @@ export function isMultipartRequest(request: Request): boolean {
|
|
|
29
29
|
*
|
|
30
30
|
* @param request The `Request` object containing multipart data
|
|
31
31
|
* @param options Optional parser options, such as `maxHeaderSize` and `maxFileSize`
|
|
32
|
-
* @
|
|
32
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
33
33
|
*/
|
|
34
34
|
export async function* parseMultipartRequest(
|
|
35
35
|
request: Request,
|
|
@@ -17,7 +17,7 @@ import { getMultipartBoundary } from './multipart-request.ts'
|
|
|
17
17
|
*
|
|
18
18
|
* @param message The multipart message as a `Buffer` or an iterable of `Buffer` chunks
|
|
19
19
|
* @param options Options for the parser
|
|
20
|
-
* @
|
|
20
|
+
* @returns A generator yielding `MultipartPart` objects
|
|
21
21
|
*/
|
|
22
22
|
export function* parseMultipart(
|
|
23
23
|
message: Buffer | Iterable<Buffer>,
|
|
@@ -34,7 +34,7 @@ export function* parseMultipart(
|
|
|
34
34
|
*
|
|
35
35
|
* @param stream A Node.js `Readable` stream containing multipart data
|
|
36
36
|
* @param options Options for the parser
|
|
37
|
-
* @
|
|
37
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
38
38
|
*/
|
|
39
39
|
export async function* parseMultipartStream(
|
|
40
40
|
stream: Readable,
|
|
@@ -47,7 +47,7 @@ export async function* parseMultipartStream(
|
|
|
47
47
|
* Returns true if the given request is a multipart request.
|
|
48
48
|
*
|
|
49
49
|
* @param req The Node.js `http.IncomingMessage` object to check
|
|
50
|
-
* @
|
|
50
|
+
* @returns `true` if the request is a multipart request, `false` otherwise
|
|
51
51
|
*/
|
|
52
52
|
export function isMultipartRequest(req: http.IncomingMessage): boolean {
|
|
53
53
|
let contentType = req.headers['content-type']
|
|
@@ -59,7 +59,7 @@ export function isMultipartRequest(req: http.IncomingMessage): boolean {
|
|
|
59
59
|
*
|
|
60
60
|
* @param req The Node.js `http.IncomingMessage` object containing multipart data
|
|
61
61
|
* @param options Options for the parser
|
|
62
|
-
* @
|
|
62
|
+
* @returns An async generator yielding `MultipartPart` objects
|
|
63
63
|
*/
|
|
64
64
|
export async function* parseMultipartRequest(
|
|
65
65
|
req: http.IncomingMessage,
|
package/src/lib/multipart.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ContentDisposition, ContentType, parse as parseRawHeaders } from '@remix-run/headers'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
createSearch,
|
|
@@ -80,7 +80,7 @@ export interface ParseMultipartOptions {
|
|
|
80
80
|
*
|
|
81
81
|
* @param message The multipart message as a `Uint8Array` or an iterable of `Uint8Array` chunks
|
|
82
82
|
* @param options Options for the parser
|
|
83
|
-
* @
|
|
83
|
+
* @returns A generator that yields `MultipartPart` objects
|
|
84
84
|
*/
|
|
85
85
|
export function* parseMultipart(
|
|
86
86
|
message: Uint8Array | Iterable<Uint8Array>,
|
|
@@ -114,7 +114,7 @@ export function* parseMultipart(
|
|
|
114
114
|
*
|
|
115
115
|
* @param stream A stream containing multipart data as a `ReadableStream<Uint8Array>`
|
|
116
116
|
* @param options Options for the parser
|
|
117
|
-
* @
|
|
117
|
+
* @returns An async generator that yields `MultipartPart` objects
|
|
118
118
|
*/
|
|
119
119
|
export async function* parseMultipartStream(
|
|
120
120
|
stream: ReadableStream<Uint8Array>,
|
|
@@ -191,7 +191,7 @@ export class MultipartParser {
|
|
|
191
191
|
* Write a chunk of data to the parser.
|
|
192
192
|
*
|
|
193
193
|
* @param chunk A chunk of data to write to the parser
|
|
194
|
-
* @
|
|
194
|
+
* @returns A generator yielding `MultipartPart` objects as they are parsed
|
|
195
195
|
*/
|
|
196
196
|
*write(chunk: Uint8Array): Generator<MultipartPart, void, unknown> {
|
|
197
197
|
if (this.#state === MultipartParserStateDone) {
|
|
@@ -320,8 +320,6 @@ export class MultipartParser {
|
|
|
320
320
|
*
|
|
321
321
|
* Note: This will throw if the multipart message is incomplete or
|
|
322
322
|
* wasn't properly terminated.
|
|
323
|
-
*
|
|
324
|
-
* @return void
|
|
325
323
|
*/
|
|
326
324
|
finish(): void {
|
|
327
325
|
if (this.#state !== MultipartParserStateDone) {
|
|
@@ -381,7 +379,7 @@ export class MultipartPart {
|
|
|
381
379
|
*/
|
|
382
380
|
get headers(): Headers {
|
|
383
381
|
if (!this.#headers) {
|
|
384
|
-
this.#headers =
|
|
382
|
+
this.#headers = parseRawHeaders(decoder.decode(this.#header))
|
|
385
383
|
}
|
|
386
384
|
|
|
387
385
|
return this.#headers
|
|
@@ -405,21 +403,21 @@ export class MultipartPart {
|
|
|
405
403
|
* The filename of the part, if it is a file upload.
|
|
406
404
|
*/
|
|
407
405
|
get filename(): string | undefined {
|
|
408
|
-
return this.headers.
|
|
406
|
+
return ContentDisposition.from(this.headers.get('content-disposition')).preferredFilename
|
|
409
407
|
}
|
|
410
408
|
|
|
411
409
|
/**
|
|
412
410
|
* The media type of the part.
|
|
413
411
|
*/
|
|
414
412
|
get mediaType(): string | undefined {
|
|
415
|
-
return this.headers.
|
|
413
|
+
return ContentType.from(this.headers.get('content-type')).mediaType
|
|
416
414
|
}
|
|
417
415
|
|
|
418
416
|
/**
|
|
419
417
|
* The name of the part, usually the `name` of the field in the `<form>` that submitted the request.
|
|
420
418
|
*/
|
|
421
419
|
get name(): string | undefined {
|
|
422
|
-
return this.headers.
|
|
420
|
+
return ContentDisposition.from(this.headers.get('content-disposition')).name
|
|
423
421
|
}
|
|
424
422
|
|
|
425
423
|
/**
|