@@ -7,10 +7,11 @@ const {
7
7
ObjectDefineProperty,
8
8
PromiseResolve,
9
9
PromiseReject,
10
- PromisePrototypeFinally ,
10
+ SafePromisePrototypeFinally ,
11
11
ReflectConstruct,
12
12
RegExpPrototypeTest,
13
13
StringPrototypeToLowerCase,
14
+ StringPrototypeSplit,
14
15
Symbol,
15
16
SymbolIterator,
16
17
SymbolToStringTag,
@@ -20,7 +21,8 @@ const {
20
21
const {
21
22
createBlob : _createBlob ,
22
23
FixedSizeBlobCopyJob,
23
- } = internalBinding ( 'buffer' ) ;
24
+ getDataObject,
25
+ } = internalBinding ( 'blob' ) ;
24
26
25
27
const { TextDecoder } = require ( 'internal/encoding' ) ;
26
28
@@ -57,26 +59,37 @@ const {
57
59
} = require ( 'internal/validators' ) ;
58
60
59
61
const kHandle = Symbol ( 'kHandle' ) ;
62
+ const kState = Symbol ( 'kState' ) ;
60
63
const kType = Symbol ( 'kType' ) ;
61
64
const kLength = Symbol ( 'kLength' ) ;
62
65
const kArrayBufferPromise = Symbol ( 'kArrayBufferPromise' ) ;
63
66
67
+ const kMaxChunkSize = 65536 ;
68
+
64
69
const disallowedTypeCharacters = / [ ^ \u{0020} - \u{007E} ] / u;
65
70
66
71
let Buffer ;
67
72
let ReadableStream ;
73
+ let URL ;
74
+
75
+
76
+ // Yes, lazy loading is annoying but because of circular
77
+ // references between the url, internal/blob, and buffer
78
+ // modules, lazy loading here makes sure that things work.
79
+
80
+ function lazyURL ( id ) {
81
+ URL ??= require ( 'internal/url' ) . URL ;
82
+ return new URL ( id ) ;
83
+ }
68
84
69
85
function lazyBuffer ( ) {
70
- if ( Buffer === undefined )
71
- Buffer = require ( 'buffer' ) . Buffer ;
86
+ Buffer ??= require ( 'buffer' ) . Buffer ;
72
87
return Buffer ;
73
88
}
74
89
75
90
function lazyReadableStream ( options ) {
76
- if ( ReadableStream === undefined ) {
77
- ReadableStream =
78
- require ( 'internal/webstreams/readablestream' ) . ReadableStream ;
79
- }
91
+ ReadableStream ??=
92
+ require ( 'internal/webstreams/readablestream' ) . ReadableStream ;
80
93
return new ReadableStream ( options ) ;
81
94
}
82
95
@@ -232,9 +245,9 @@ class Blob {
232
245
return PromiseReject ( new ERR_INVALID_THIS ( 'Blob' ) ) ;
233
246
234
247
// If there's already a promise in flight for the content,
235
- // reuse it, but only once . After the cached promise resolves
236
- // it will be cleared, allowing it to be garbage collected
237
- // as soon as possible.
248
+ // reuse it, but only while it's in flight . After the cached
249
+ // promise resolves it will be cleared, allowing it to be
250
+ // garbage collected as soon as possible.
238
251
if ( this [ kArrayBufferPromise ] )
239
252
return this [ kArrayBufferPromise ] ;
240
253
@@ -260,15 +273,14 @@ class Blob {
260
273
resolve ( ab ) ;
261
274
} ;
262
275
this [ kArrayBufferPromise ] =
263
- PromisePrototypeFinally (
276
+ SafePromisePrototypeFinally (
264
277
promise ,
265
278
( ) => this [ kArrayBufferPromise ] = undefined ) ;
266
279
267
280
return this [ kArrayBufferPromise ] ;
268
281
}
269
282
270
283
/**
271
- *
272
284
* @returns {Promise<string> }
273
285
*/
274
286
async text ( ) {
@@ -288,10 +300,20 @@ class Blob {
288
300
289
301
const self = this ;
290
302
return new lazyReadableStream ( {
291
- async start ( controller ) {
292
- const ab = await self . arrayBuffer ( ) ;
293
- controller . enqueue ( new Uint8Array ( ab ) ) ;
294
- controller . close ( ) ;
303
+ async start ( ) {
304
+ this [ kState ] = await self . arrayBuffer ( ) ;
305
+ } ,
306
+
307
+ pull ( controller ) {
308
+ if ( this [ kState ] . byteLength <= kMaxChunkSize ) {
309
+ controller . enqueue ( new Uint8Array ( this [ kState ] ) ) ;
310
+ controller . close ( ) ;
311
+ this [ kState ] = undefined ;
312
+ } else {
313
+ const slice = this [ kState ] . slice ( 0 , kMaxChunkSize ) ;
314
+ this [ kState ] = this [ kState ] . slice ( kMaxChunkSize ) ;
315
+ controller . enqueue ( new Uint8Array ( slice ) ) ;
316
+ }
295
317
}
296
318
} ) ;
297
319
}
@@ -315,9 +337,47 @@ ObjectDefineProperty(Blob.prototype, SymbolToStringTag, {
315
337
value : 'Blob' ,
316
338
} ) ;
317
339
340
+ function resolveObjectURL ( url ) {
341
+ url = `${ url } ` ;
342
+ try {
343
+ const parsed = new lazyURL ( url ) ;
344
+
345
+ const split = StringPrototypeSplit ( parsed . pathname , ':' ) ;
346
+
347
+ if ( split . length !== 2 )
348
+ return ;
349
+
350
+ const {
351
+ 0 : base ,
352
+ 1 : id ,
353
+ } = split ;
354
+
355
+ if ( base !== 'nodedata' )
356
+ return ;
357
+
358
+ const ret = getDataObject ( id ) ;
359
+
360
+ if ( ret === undefined )
361
+ return ;
362
+
363
+ const {
364
+ 0 : handle ,
365
+ 1 : length ,
366
+ 2 : type ,
367
+ } = ret ;
368
+
369
+ if ( handle !== undefined )
370
+ return createBlob ( handle , length , type ) ;
371
+ } catch {
372
+ // If there's an error, it's ignored and nothing is returned
373
+ }
374
+ }
375
+
318
376
module . exports = {
319
377
Blob,
320
378
ClonedBlob,
321
379
createBlob,
322
380
isBlob,
381
+ kHandle,
382
+ resolveObjectURL,
323
383
} ;
0 commit comments