@remix-run/multipart-parser 0.11.0 → 0.13.0
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/LICENSE +1 -1
- package/README.md +39 -45
- package/dist/{multipart-parser.d.ts → index.d.ts} +1 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/lib/buffer-search.d.ts.map +1 -1
- package/dist/lib/buffer-search.js +51 -0
- package/dist/lib/multipart-request.d.ts.map +1 -1
- package/dist/lib/multipart-request.js +46 -0
- package/dist/lib/multipart.d.ts.map +1 -1
- package/dist/lib/multipart.js +320 -0
- package/dist/lib/multipart.node.d.ts.map +1 -1
- package/dist/lib/multipart.node.js +60 -0
- package/dist/lib/read-stream.js +16 -0
- package/dist/{multipart-parser.node.d.ts → node.d.ts} +2 -2
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +4 -0
- package/package.json +13 -24
- package/src/{multipart-parser.ts → index.ts} +3 -3
- package/src/lib/buffer-search.ts +25 -25
- package/src/lib/multipart-request.ts +11 -11
- package/src/lib/multipart.node.ts +13 -13
- package/src/lib/multipart.ts +123 -123
- package/src/lib/read-stream.ts +5 -5
- package/src/{multipart-parser.node.ts → node.ts} +9 -4
- package/dist/multipart-parser.cjs +0 -2021
- package/dist/multipart-parser.cjs.map +0 -7
- package/dist/multipart-parser.d.ts.map +0 -1
- package/dist/multipart-parser.js +0 -1985
- package/dist/multipart-parser.js.map +0 -7
- package/dist/multipart-parser.node.cjs +0 -2027
- package/dist/multipart-parser.node.cjs.map +0 -7
- package/dist/multipart-parser.node.d.ts.map +0 -1
- package/dist/multipart-parser.node.js +0 -1991
- package/dist/multipart-parser.node.js.map +0 -7
package/src/lib/multipart.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import Headers from '@remix-run/headers'
|
|
1
|
+
import Headers from '@remix-run/headers'
|
|
2
2
|
|
|
3
|
-
import { readStream } from './read-stream.ts'
|
|
4
|
-
import type { SearchFunction, PartialTailSearchFunction } from './buffer-search.ts'
|
|
5
|
-
import { createSearch, createPartialTailSearch } from './buffer-search.ts'
|
|
3
|
+
import { readStream } from './read-stream.ts'
|
|
4
|
+
import type { SearchFunction, PartialTailSearchFunction } from './buffer-search.ts'
|
|
5
|
+
import { createSearch, createPartialTailSearch } from './buffer-search.ts'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The base class for errors thrown by the multipart parser.
|
|
9
9
|
*/
|
|
10
10
|
export class MultipartParseError extends Error {
|
|
11
11
|
constructor(message: string) {
|
|
12
|
-
super(message)
|
|
13
|
-
this.name = 'MultipartParseError'
|
|
12
|
+
super(message)
|
|
13
|
+
this.name = 'MultipartParseError'
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -19,8 +19,8 @@ export class MultipartParseError extends Error {
|
|
|
19
19
|
*/
|
|
20
20
|
export class MaxHeaderSizeExceededError extends MultipartParseError {
|
|
21
21
|
constructor(maxHeaderSize: number) {
|
|
22
|
-
super(`Multipart header size exceeds maximum allowed size of ${maxHeaderSize} bytes`)
|
|
23
|
-
this.name = 'MaxHeaderSizeExceededError'
|
|
22
|
+
super(`Multipart header size exceeds maximum allowed size of ${maxHeaderSize} bytes`)
|
|
23
|
+
this.name = 'MaxHeaderSizeExceededError'
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -29,8 +29,8 @@ export class MaxHeaderSizeExceededError extends MultipartParseError {
|
|
|
29
29
|
*/
|
|
30
30
|
export class MaxFileSizeExceededError extends MultipartParseError {
|
|
31
31
|
constructor(maxFileSize: number) {
|
|
32
|
-
super(`File size exceeds maximum allowed size of ${maxFileSize} bytes`)
|
|
33
|
-
this.name = 'MaxFileSizeExceededError'
|
|
32
|
+
super(`File size exceeds maximum allowed size of ${maxFileSize} bytes`)
|
|
33
|
+
this.name = 'MaxFileSizeExceededError'
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -39,21 +39,21 @@ export interface ParseMultipartOptions {
|
|
|
39
39
|
* The boundary string used to separate parts in the multipart message,
|
|
40
40
|
* e.g. the `boundary` parameter in the `Content-Type` header.
|
|
41
41
|
*/
|
|
42
|
-
boundary: string
|
|
42
|
+
boundary: string
|
|
43
43
|
/**
|
|
44
44
|
* The maximum allowed size of a header in bytes. If an individual part's header
|
|
45
45
|
* exceeds this size, a `MaxHeaderSizeExceededError` will be thrown.
|
|
46
46
|
*
|
|
47
47
|
* Default: 8 KiB
|
|
48
48
|
*/
|
|
49
|
-
maxHeaderSize?: number
|
|
49
|
+
maxHeaderSize?: number
|
|
50
50
|
/**
|
|
51
51
|
* The maximum allowed size of a file in bytes. If an individual part's content
|
|
52
52
|
* exceeds this size, a `MaxFileSizeExceededError` will be thrown.
|
|
53
53
|
*
|
|
54
54
|
* Default: 2 MiB
|
|
55
55
|
*/
|
|
56
|
-
maxFileSize?: number
|
|
56
|
+
maxFileSize?: number
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
@@ -73,21 +73,21 @@ export function* parseMultipart(
|
|
|
73
73
|
let parser = new MultipartParser(options.boundary, {
|
|
74
74
|
maxHeaderSize: options.maxHeaderSize,
|
|
75
75
|
maxFileSize: options.maxFileSize,
|
|
76
|
-
})
|
|
76
|
+
})
|
|
77
77
|
|
|
78
78
|
if (message instanceof Uint8Array) {
|
|
79
79
|
if (message.length === 0) {
|
|
80
|
-
return
|
|
80
|
+
return // No data to parse
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
yield* parser.write(message)
|
|
83
|
+
yield* parser.write(message)
|
|
84
84
|
} else {
|
|
85
85
|
for (let chunk of message) {
|
|
86
|
-
yield* parser.write(chunk)
|
|
86
|
+
yield* parser.write(chunk)
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
parser.finish()
|
|
90
|
+
parser.finish()
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
@@ -107,61 +107,61 @@ export async function* parseMultipartStream(
|
|
|
107
107
|
let parser = new MultipartParser(options.boundary, {
|
|
108
108
|
maxHeaderSize: options.maxHeaderSize,
|
|
109
109
|
maxFileSize: options.maxFileSize,
|
|
110
|
-
})
|
|
110
|
+
})
|
|
111
111
|
|
|
112
112
|
for await (let chunk of readStream(stream)) {
|
|
113
113
|
if (chunk.length === 0) {
|
|
114
|
-
continue
|
|
114
|
+
continue // No data to parse
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
yield* parser.write(chunk)
|
|
117
|
+
yield* parser.write(chunk)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
parser.finish()
|
|
120
|
+
parser.finish()
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
export type MultipartParserOptions = Omit<ParseMultipartOptions, 'boundary'
|
|
123
|
+
export type MultipartParserOptions = Omit<ParseMultipartOptions, 'boundary'>
|
|
124
124
|
|
|
125
|
-
const MultipartParserStateStart = 0
|
|
126
|
-
const MultipartParserStateAfterBoundary = 1
|
|
127
|
-
const MultipartParserStateHeader = 2
|
|
128
|
-
const MultipartParserStateBody = 3
|
|
129
|
-
const MultipartParserStateDone = 4
|
|
125
|
+
const MultipartParserStateStart = 0
|
|
126
|
+
const MultipartParserStateAfterBoundary = 1
|
|
127
|
+
const MultipartParserStateHeader = 2
|
|
128
|
+
const MultipartParserStateBody = 3
|
|
129
|
+
const MultipartParserStateDone = 4
|
|
130
130
|
|
|
131
|
-
const findDoubleNewline = createSearch('\r\n\r\n')
|
|
131
|
+
const findDoubleNewline = createSearch('\r\n\r\n')
|
|
132
132
|
|
|
133
|
-
const oneKb = 1024
|
|
134
|
-
const oneMb = 1024 * oneKb
|
|
133
|
+
const oneKb = 1024
|
|
134
|
+
const oneMb = 1024 * oneKb
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
137
|
* A streaming parser for `multipart/*` HTTP messages.
|
|
138
138
|
*/
|
|
139
139
|
export class MultipartParser {
|
|
140
|
-
readonly boundary: string
|
|
141
|
-
readonly maxHeaderSize: number
|
|
142
|
-
readonly maxFileSize: number
|
|
140
|
+
readonly boundary: string
|
|
141
|
+
readonly maxHeaderSize: number
|
|
142
|
+
readonly maxFileSize: number
|
|
143
143
|
|
|
144
|
-
#findOpeningBoundary: SearchFunction
|
|
145
|
-
#openingBoundaryLength: number
|
|
146
|
-
#findBoundary: SearchFunction
|
|
147
|
-
#findPartialTailBoundary: PartialTailSearchFunction
|
|
148
|
-
#boundaryLength: number
|
|
144
|
+
#findOpeningBoundary: SearchFunction
|
|
145
|
+
#openingBoundaryLength: number
|
|
146
|
+
#findBoundary: SearchFunction
|
|
147
|
+
#findPartialTailBoundary: PartialTailSearchFunction
|
|
148
|
+
#boundaryLength: number
|
|
149
149
|
|
|
150
|
-
#state = MultipartParserStateStart
|
|
151
|
-
#buffer: Uint8Array | null = null
|
|
152
|
-
#currentPart: MultipartPart | null = null
|
|
153
|
-
#contentLength = 0
|
|
150
|
+
#state = MultipartParserStateStart
|
|
151
|
+
#buffer: Uint8Array | null = null
|
|
152
|
+
#currentPart: MultipartPart | null = null
|
|
153
|
+
#contentLength = 0
|
|
154
154
|
|
|
155
155
|
constructor(boundary: string, options?: MultipartParserOptions) {
|
|
156
|
-
this.boundary = boundary
|
|
157
|
-
this.maxHeaderSize = options?.maxHeaderSize ?? 8 * oneKb
|
|
158
|
-
this.maxFileSize = options?.maxFileSize ?? 2 * oneMb
|
|
159
|
-
|
|
160
|
-
this.#findOpeningBoundary = createSearch(`--${boundary}`)
|
|
161
|
-
this.#openingBoundaryLength = 2 + boundary.length
|
|
162
|
-
this.#findBoundary = createSearch(`\r\n--${boundary}`)
|
|
163
|
-
this.#findPartialTailBoundary = createPartialTailSearch(`\r\n--${boundary}`)
|
|
164
|
-
this.#boundaryLength = 4 + boundary.length
|
|
156
|
+
this.boundary = boundary
|
|
157
|
+
this.maxHeaderSize = options?.maxHeaderSize ?? 8 * oneKb
|
|
158
|
+
this.maxFileSize = options?.maxFileSize ?? 2 * oneMb
|
|
159
|
+
|
|
160
|
+
this.#findOpeningBoundary = createSearch(`--${boundary}`)
|
|
161
|
+
this.#openingBoundaryLength = 2 + boundary.length // length of '--' + boundary
|
|
162
|
+
this.#findBoundary = createSearch(`\r\n--${boundary}`)
|
|
163
|
+
this.#findPartialTailBoundary = createPartialTailSearch(`\r\n--${boundary}`)
|
|
164
|
+
this.#boundaryLength = 4 + boundary.length // length of '\r\n--' + boundary
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/**
|
|
@@ -172,124 +172,124 @@ export class MultipartParser {
|
|
|
172
172
|
*/
|
|
173
173
|
*write(chunk: Uint8Array): Generator<MultipartPart, void, unknown> {
|
|
174
174
|
if (this.#state === MultipartParserStateDone) {
|
|
175
|
-
throw new MultipartParseError('Unexpected data after end of stream')
|
|
175
|
+
throw new MultipartParseError('Unexpected data after end of stream')
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
let index = 0
|
|
179
|
-
let chunkLength = chunk.length
|
|
178
|
+
let index = 0
|
|
179
|
+
let chunkLength = chunk.length
|
|
180
180
|
|
|
181
181
|
if (this.#buffer !== null) {
|
|
182
|
-
let newChunk = new Uint8Array(this.#buffer.length + chunkLength)
|
|
183
|
-
newChunk.set(this.#buffer, 0)
|
|
184
|
-
newChunk.set(chunk, this.#buffer.length)
|
|
185
|
-
chunk = newChunk
|
|
186
|
-
chunkLength = chunk.length
|
|
187
|
-
this.#buffer = null
|
|
182
|
+
let newChunk = new Uint8Array(this.#buffer.length + chunkLength)
|
|
183
|
+
newChunk.set(this.#buffer, 0)
|
|
184
|
+
newChunk.set(chunk, this.#buffer.length)
|
|
185
|
+
chunk = newChunk
|
|
186
|
+
chunkLength = chunk.length
|
|
187
|
+
this.#buffer = null
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
while (true) {
|
|
191
191
|
if (this.#state === MultipartParserStateBody) {
|
|
192
192
|
if (chunkLength - index < this.#boundaryLength) {
|
|
193
|
-
this.#buffer = chunk.subarray(index)
|
|
194
|
-
break
|
|
193
|
+
this.#buffer = chunk.subarray(index)
|
|
194
|
+
break
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
let boundaryIndex = this.#findBoundary(chunk, index)
|
|
197
|
+
let boundaryIndex = this.#findBoundary(chunk, index)
|
|
198
198
|
|
|
199
199
|
if (boundaryIndex === -1) {
|
|
200
200
|
// No boundary found, but there may be a partial match at the end of the chunk.
|
|
201
|
-
let partialTailIndex = this.#findPartialTailBoundary(chunk)
|
|
201
|
+
let partialTailIndex = this.#findPartialTailBoundary(chunk)
|
|
202
202
|
|
|
203
203
|
if (partialTailIndex === -1) {
|
|
204
|
-
this.#append(index === 0 ? chunk : chunk.subarray(index))
|
|
204
|
+
this.#append(index === 0 ? chunk : chunk.subarray(index))
|
|
205
205
|
} else {
|
|
206
|
-
this.#append(chunk.subarray(index, partialTailIndex))
|
|
207
|
-
this.#buffer = chunk.subarray(partialTailIndex)
|
|
206
|
+
this.#append(chunk.subarray(index, partialTailIndex))
|
|
207
|
+
this.#buffer = chunk.subarray(partialTailIndex)
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
break
|
|
210
|
+
break
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
this.#append(chunk.subarray(index, boundaryIndex))
|
|
213
|
+
this.#append(chunk.subarray(index, boundaryIndex))
|
|
214
214
|
|
|
215
|
-
yield this.#currentPart
|
|
215
|
+
yield this.#currentPart!
|
|
216
216
|
|
|
217
|
-
index = boundaryIndex + this.#boundaryLength
|
|
217
|
+
index = boundaryIndex + this.#boundaryLength
|
|
218
218
|
|
|
219
|
-
this.#state = MultipartParserStateAfterBoundary
|
|
219
|
+
this.#state = MultipartParserStateAfterBoundary
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
if (this.#state === MultipartParserStateAfterBoundary) {
|
|
223
223
|
if (chunkLength - index < 2) {
|
|
224
|
-
this.#buffer = chunk.subarray(index)
|
|
225
|
-
break
|
|
224
|
+
this.#buffer = chunk.subarray(index)
|
|
225
|
+
break
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
if (chunk[index] === 45 && chunk[index + 1] === 45) {
|
|
229
|
-
this.#state = MultipartParserStateDone
|
|
230
|
-
break
|
|
229
|
+
this.#state = MultipartParserStateDone
|
|
230
|
+
break
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
index += 2
|
|
233
|
+
index += 2 // Skip \r\n after boundary
|
|
234
234
|
|
|
235
|
-
this.#state = MultipartParserStateHeader
|
|
235
|
+
this.#state = MultipartParserStateHeader
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
if (this.#state === MultipartParserStateHeader) {
|
|
239
239
|
if (chunkLength - index < 4) {
|
|
240
|
-
this.#buffer = chunk.subarray(index)
|
|
241
|
-
break
|
|
240
|
+
this.#buffer = chunk.subarray(index)
|
|
241
|
+
break
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
let headerEndIndex = findDoubleNewline(chunk, index)
|
|
244
|
+
let headerEndIndex = findDoubleNewline(chunk, index)
|
|
245
245
|
|
|
246
246
|
if (headerEndIndex === -1) {
|
|
247
247
|
if (chunkLength - index > this.maxHeaderSize) {
|
|
248
|
-
throw new MaxHeaderSizeExceededError(this.maxHeaderSize)
|
|
248
|
+
throw new MaxHeaderSizeExceededError(this.maxHeaderSize)
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
this.#buffer = chunk.subarray(index)
|
|
252
|
-
break
|
|
251
|
+
this.#buffer = chunk.subarray(index)
|
|
252
|
+
break
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
if (headerEndIndex - index > this.maxHeaderSize) {
|
|
256
|
-
throw new MaxHeaderSizeExceededError(this.maxHeaderSize)
|
|
256
|
+
throw new MaxHeaderSizeExceededError(this.maxHeaderSize)
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
this.#currentPart = new MultipartPart(chunk.subarray(index, headerEndIndex), [])
|
|
260
|
-
this.#contentLength = 0
|
|
259
|
+
this.#currentPart = new MultipartPart(chunk.subarray(index, headerEndIndex), [])
|
|
260
|
+
this.#contentLength = 0
|
|
261
261
|
|
|
262
|
-
index = headerEndIndex + 4
|
|
262
|
+
index = headerEndIndex + 4 // Skip header + \r\n\r\n
|
|
263
263
|
|
|
264
|
-
this.#state = MultipartParserStateBody
|
|
264
|
+
this.#state = MultipartParserStateBody
|
|
265
265
|
|
|
266
|
-
continue
|
|
266
|
+
continue
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
if (this.#state === MultipartParserStateStart) {
|
|
270
270
|
if (chunkLength < this.#openingBoundaryLength) {
|
|
271
|
-
this.#buffer = chunk
|
|
272
|
-
break
|
|
271
|
+
this.#buffer = chunk
|
|
272
|
+
break
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
if (this.#findOpeningBoundary(chunk) !== 0) {
|
|
276
|
-
throw new MultipartParseError('Invalid multipart stream: missing initial boundary')
|
|
276
|
+
throw new MultipartParseError('Invalid multipart stream: missing initial boundary')
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
index = this.#openingBoundaryLength
|
|
279
|
+
index = this.#openingBoundaryLength
|
|
280
280
|
|
|
281
|
-
this.#state = MultipartParserStateAfterBoundary
|
|
281
|
+
this.#state = MultipartParserStateAfterBoundary
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
#append(chunk: Uint8Array): void {
|
|
287
287
|
if (this.#contentLength + chunk.length > this.maxFileSize) {
|
|
288
|
-
throw new MaxFileSizeExceededError(this.maxFileSize)
|
|
288
|
+
throw new MaxFileSizeExceededError(this.maxFileSize)
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
this.#currentPart!.content.push(chunk)
|
|
292
|
-
this.#contentLength += chunk.length
|
|
291
|
+
this.#currentPart!.content.push(chunk)
|
|
292
|
+
this.#contentLength += chunk.length
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
/**
|
|
@@ -302,12 +302,12 @@ export class MultipartParser {
|
|
|
302
302
|
*/
|
|
303
303
|
finish(): void {
|
|
304
304
|
if (this.#state !== MultipartParserStateDone) {
|
|
305
|
-
throw new MultipartParseError('Multipart stream not finished')
|
|
305
|
+
throw new MultipartParseError('Multipart stream not finished')
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
const decoder = new TextDecoder('utf-8', { fatal: true })
|
|
310
|
+
const decoder = new TextDecoder('utf-8', { fatal: true })
|
|
311
311
|
|
|
312
312
|
/**
|
|
313
313
|
* A part of a `multipart/*` HTTP message.
|
|
@@ -316,21 +316,21 @@ export class MultipartPart {
|
|
|
316
316
|
/**
|
|
317
317
|
* The raw content of this part as an array of `Uint8Array` chunks.
|
|
318
318
|
*/
|
|
319
|
-
readonly content: Uint8Array[]
|
|
319
|
+
readonly content: Uint8Array[]
|
|
320
320
|
|
|
321
|
-
#header: Uint8Array
|
|
322
|
-
#headers?: Headers
|
|
321
|
+
#header: Uint8Array
|
|
322
|
+
#headers?: Headers
|
|
323
323
|
|
|
324
324
|
constructor(header: Uint8Array, content: Uint8Array[]) {
|
|
325
|
-
this.#header = header
|
|
326
|
-
this.content = content
|
|
325
|
+
this.#header = header
|
|
326
|
+
this.content = content
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
/**
|
|
330
330
|
* The content of this part as an `ArrayBuffer`.
|
|
331
331
|
*/
|
|
332
332
|
get arrayBuffer(): ArrayBuffer {
|
|
333
|
-
return this.bytes.buffer as ArrayBuffer
|
|
333
|
+
return this.bytes.buffer as ArrayBuffer
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
/**
|
|
@@ -338,15 +338,15 @@ export class MultipartPart {
|
|
|
338
338
|
* for reading the value of files that were uploaded using `<input type="file">` fields.
|
|
339
339
|
*/
|
|
340
340
|
get bytes(): Uint8Array {
|
|
341
|
-
let buffer = new Uint8Array(this.size)
|
|
341
|
+
let buffer = new Uint8Array(this.size)
|
|
342
342
|
|
|
343
|
-
let offset = 0
|
|
343
|
+
let offset = 0
|
|
344
344
|
for (let chunk of this.content) {
|
|
345
|
-
buffer.set(chunk, offset)
|
|
346
|
-
offset += chunk.length
|
|
345
|
+
buffer.set(chunk, offset)
|
|
346
|
+
offset += chunk.length
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
return buffer
|
|
349
|
+
return buffer
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
/**
|
|
@@ -354,58 +354,58 @@ export class MultipartPart {
|
|
|
354
354
|
*/
|
|
355
355
|
get headers(): Headers {
|
|
356
356
|
if (!this.#headers) {
|
|
357
|
-
this.#headers = new Headers(decoder.decode(this.#header))
|
|
357
|
+
this.#headers = new Headers(decoder.decode(this.#header))
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
return this.#headers
|
|
360
|
+
return this.#headers
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
/**
|
|
364
364
|
* True if this part originated from a file upload.
|
|
365
365
|
*/
|
|
366
366
|
get isFile(): boolean {
|
|
367
|
-
return this.filename !== undefined || this.mediaType === 'application/octet-stream'
|
|
367
|
+
return this.filename !== undefined || this.mediaType === 'application/octet-stream'
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
/**
|
|
371
371
|
* True if this part originated from a text input field in a form submission.
|
|
372
372
|
*/
|
|
373
373
|
get isText(): boolean {
|
|
374
|
-
return !this.isFile
|
|
374
|
+
return !this.isFile
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
/**
|
|
378
378
|
* The filename of the part, if it is a file upload.
|
|
379
379
|
*/
|
|
380
380
|
get filename(): string | undefined {
|
|
381
|
-
return this.headers.contentDisposition.preferredFilename
|
|
381
|
+
return this.headers.contentDisposition.preferredFilename
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
/**
|
|
385
385
|
* The media type of the part.
|
|
386
386
|
*/
|
|
387
387
|
get mediaType(): string | undefined {
|
|
388
|
-
return this.headers.contentType.mediaType
|
|
388
|
+
return this.headers.contentType.mediaType
|
|
389
389
|
}
|
|
390
390
|
|
|
391
391
|
/**
|
|
392
392
|
* The name of the part, usually the `name` of the field in the `<form>` that submitted the request.
|
|
393
393
|
*/
|
|
394
394
|
get name(): string | undefined {
|
|
395
|
-
return this.headers.contentDisposition.name
|
|
395
|
+
return this.headers.contentDisposition.name
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
/**
|
|
399
399
|
* The size of the content in bytes.
|
|
400
400
|
*/
|
|
401
401
|
get size(): number {
|
|
402
|
-
let size = 0
|
|
402
|
+
let size = 0
|
|
403
403
|
|
|
404
404
|
for (let chunk of this.content) {
|
|
405
|
-
size += chunk.length
|
|
405
|
+
size += chunk.length
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
return size
|
|
408
|
+
return size
|
|
409
409
|
}
|
|
410
410
|
|
|
411
411
|
/**
|
|
@@ -415,6 +415,6 @@ export class MultipartPart {
|
|
|
415
415
|
* Note: Do not use this for binary data, use `part.bytes` or `part.arrayBuffer` instead.
|
|
416
416
|
*/
|
|
417
417
|
get text(): string {
|
|
418
|
-
return decoder.decode(this.bytes)
|
|
418
|
+
return decoder.decode(this.bytes)
|
|
419
419
|
}
|
|
420
420
|
}
|
package/src/lib/read-stream.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// We need this little helper for environments that do not support
|
|
2
2
|
// ReadableStream.prototype[Symbol.asyncIterator] yet. See #46
|
|
3
3
|
export async function* readStream(stream: ReadableStream<Uint8Array>): AsyncIterable<Uint8Array> {
|
|
4
|
-
let reader = stream.getReader()
|
|
4
|
+
let reader = stream.getReader()
|
|
5
5
|
|
|
6
6
|
try {
|
|
7
7
|
while (true) {
|
|
8
|
-
|
|
9
|
-
if (done) break
|
|
10
|
-
yield value
|
|
8
|
+
let result = await reader.read()
|
|
9
|
+
if (result.done) break
|
|
10
|
+
yield result.value
|
|
11
11
|
}
|
|
12
12
|
} finally {
|
|
13
|
-
reader.releaseLock()
|
|
13
|
+
reader.releaseLock()
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
// Re-export all core functionality
|
|
2
|
-
export type { ParseMultipartOptions, MultipartParserOptions } from './lib/multipart.ts'
|
|
2
|
+
export type { ParseMultipartOptions, MultipartParserOptions } from './lib/multipart.ts'
|
|
3
3
|
export {
|
|
4
4
|
MultipartParseError,
|
|
5
5
|
MaxHeaderSizeExceededError,
|
|
6
6
|
MaxFileSizeExceededError,
|
|
7
7
|
MultipartParser,
|
|
8
8
|
MultipartPart,
|
|
9
|
-
} from './lib/multipart.ts'
|
|
9
|
+
} from './lib/multipart.ts'
|
|
10
10
|
|
|
11
|
-
export { getMultipartBoundary } from './lib/multipart-request.ts'
|
|
11
|
+
export { getMultipartBoundary } from './lib/multipart-request.ts'
|
|
12
12
|
|
|
13
13
|
// Export Node.js-specific functionality
|
|
14
|
-
export {
|
|
14
|
+
export {
|
|
15
|
+
isMultipartRequest,
|
|
16
|
+
parseMultipartRequest,
|
|
17
|
+
parseMultipart,
|
|
18
|
+
parseMultipartStream,
|
|
19
|
+
} from './lib/multipart.node.ts'
|