@@ -6,8 +6,8 @@ const { Duplex } = require('stream');
6
6
const { randomFillSync } = require ( 'crypto' ) ;
7
7
8
8
const PerMessageDeflate = require ( './permessage-deflate' ) ;
9
- const { EMPTY_BUFFER } = require ( './constants' ) ;
10
- const { isValidStatusCode } = require ( './validation' ) ;
9
+ const { EMPTY_BUFFER , kWebSocket , NOOP } = require ( './constants' ) ;
10
+ const { isBlob , isValidStatusCode } = require ( './validation' ) ;
11
11
const { mask : applyMask , toBuffer } = require ( './buffer-util' ) ;
12
12
13
13
const kByteLength = Symbol ( 'kByteLength' ) ;
@@ -16,6 +16,10 @@ const RANDOM_POOL_SIZE = 8 * 1024;
16
16
let randomPool ;
17
17
let randomPoolPointer = RANDOM_POOL_SIZE ;
18
18
19
+ const DEFAULT = 0 ;
20
+ const DEFLATING = 1 ;
21
+ const GET_BLOB_DATA = 2 ;
22
+
19
23
/**
20
24
* HyBi Sender implementation.
21
25
*/
@@ -42,8 +46,10 @@ class Sender {
42
46
this . _compress = false ;
43
47
44
48
this . _bufferedBytes = 0 ;
45
- this . _deflating = false ;
46
49
this . _queue = [ ] ;
50
+ this . _state = DEFAULT ;
51
+ this . onerror = NOOP ;
52
+ this [ kWebSocket ] = undefined ;
47
53
}
48
54
49
55
/**
@@ -210,7 +216,7 @@ class Sender {
210
216
rsv1 : false
211
217
} ;
212
218
213
- if ( this . _deflating ) {
219
+ if ( this . _state !== DEFAULT ) {
214
220
this . enqueue ( [ this . dispatch , buf , false , options , cb ] ) ;
215
221
} else {
216
222
this . sendFrame ( Sender . frame ( buf , options ) , cb ) ;
@@ -232,6 +238,9 @@ class Sender {
232
238
if ( typeof data === 'string' ) {
233
239
byteLength = Buffer . byteLength ( data ) ;
234
240
readOnly = false ;
241
+ } else if ( isBlob ( data ) ) {
242
+ byteLength = data . size ;
243
+ readOnly = false ;
235
244
} else {
236
245
data = toBuffer ( data ) ;
237
246
byteLength = data . length ;
@@ -253,7 +262,13 @@ class Sender {
253
262
rsv1 : false
254
263
} ;
255
264
256
- if ( this . _deflating ) {
265
+ if ( isBlob ( data ) ) {
266
+ if ( this . _state !== DEFAULT ) {
267
+ this . enqueue ( [ this . getBlobData , data , false , options , cb ] ) ;
268
+ } else {
269
+ this . getBlobData ( data , false , options , cb ) ;
270
+ }
271
+ } else if ( this . _state !== DEFAULT ) {
257
272
this . enqueue ( [ this . dispatch , data , false , options , cb ] ) ;
258
273
} else {
259
274
this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
@@ -275,6 +290,9 @@ class Sender {
275
290
if ( typeof data === 'string' ) {
276
291
byteLength = Buffer . byteLength ( data ) ;
277
292
readOnly = false ;
293
+ } else if ( isBlob ( data ) ) {
294
+ byteLength = data . size ;
295
+ readOnly = false ;
278
296
} else {
279
297
data = toBuffer ( data ) ;
280
298
byteLength = data . length ;
@@ -296,7 +314,13 @@ class Sender {
296
314
rsv1 : false
297
315
} ;
298
316
299
- if ( this . _deflating ) {
317
+ if ( isBlob ( data ) ) {
318
+ if ( this . _state !== DEFAULT ) {
319
+ this . enqueue ( [ this . getBlobData , data , false , options , cb ] ) ;
320
+ } else {
321
+ this . getBlobData ( data , false , options , cb ) ;
322
+ }
323
+ } else if ( this . _state !== DEFAULT ) {
300
324
this . enqueue ( [ this . dispatch , data , false , options , cb ] ) ;
301
325
} else {
302
326
this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
@@ -330,6 +354,9 @@ class Sender {
330
354
if ( typeof data === 'string' ) {
331
355
byteLength = Buffer . byteLength ( data ) ;
332
356
readOnly = false ;
357
+ } else if ( isBlob ( data ) ) {
358
+ byteLength = data . size ;
359
+ readOnly = false ;
333
360
} else {
334
361
data = toBuffer ( data ) ;
335
362
byteLength = data . length ;
@@ -357,40 +384,107 @@ class Sender {
357
384
358
385
if ( options . fin ) this . _firstFragment = true ;
359
386
360
- if ( perMessageDeflate ) {
361
- const opts = {
362
- [ kByteLength ] : byteLength ,
363
- fin : options . fin ,
364
- generateMask : this . _generateMask ,
365
- mask : options . mask ,
366
- maskBuffer : this . _maskBuffer ,
367
- opcode ,
368
- readOnly ,
369
- rsv1
370
- } ;
371
-
372
- if ( this . _deflating ) {
373
- this . enqueue ( [ this . dispatch , data , this . _compress , opts , cb ] ) ;
387
+ const opts = {
388
+ [ kByteLength ] : byteLength ,
389
+ fin : options . fin ,
390
+ generateMask : this . _generateMask ,
391
+ mask : options . mask ,
392
+ maskBuffer : this . _maskBuffer ,
393
+ opcode ,
394
+ readOnly ,
395
+ rsv1
396
+ } ;
397
+
398
+ if ( isBlob ( data ) ) {
399
+ if ( this . _state !== DEFAULT ) {
400
+ this . enqueue ( [ this . getBlobData , data , this . _compress , opts , cb ] ) ;
374
401
} else {
375
- this . dispatch ( data , this . _compress , opts , cb ) ;
402
+ this . getBlobData ( data , this . _compress , opts , cb ) ;
376
403
}
404
+ } else if ( this . _state !== DEFAULT ) {
405
+ this . enqueue ( [ this . dispatch , data , this . _compress , opts , cb ] ) ;
377
406
} else {
378
- this . sendFrame (
379
- Sender . frame ( data , {
380
- [ kByteLength ] : byteLength ,
381
- fin : options . fin ,
382
- generateMask : this . _generateMask ,
383
- mask : options . mask ,
384
- maskBuffer : this . _maskBuffer ,
385
- opcode,
386
- readOnly,
387
- rsv1 : false
388
- } ) ,
389
- cb
390
- ) ;
407
+ this . dispatch ( data , this . _compress , opts , cb ) ;
391
408
}
392
409
}
393
410
411
+ /**
412
+ * Calls queued callbacks with an error.
413
+ *
414
+ * @param {Error } err The error to call the callbacks with
415
+ * @param {Function } [cb] The first callback
416
+ * @private
417
+ */
418
+ callCallbacks ( err , cb ) {
419
+ if ( typeof cb === 'function' ) cb ( err ) ;
420
+
421
+ for ( let i = 0 ; i < this . _queue . length ; i ++ ) {
422
+ const params = this . _queue [ i ] ;
423
+ const callback = params [ params . length - 1 ] ;
424
+
425
+ if ( typeof callback === 'function' ) callback ( err ) ;
426
+ }
427
+ }
428
+
429
+ /**
430
+ * Gets the contents of a blob as binary data.
431
+ *
432
+ * @param {Blob } blob The blob
433
+ * @param {Boolean } [compress=false] Specifies whether or not to compress
434
+ * the data
435
+ * @param {Object } options Options object
436
+ * @param {Boolean } [options.fin=false] Specifies whether or not to set the
437
+ * FIN bit
438
+ * @param {Function } [options.generateMask] The function used to generate the
439
+ * masking key
440
+ * @param {Boolean } [options.mask=false] Specifies whether or not to mask
441
+ * `data`
442
+ * @param {Buffer } [options.maskBuffer] The buffer used to store the masking
443
+ * key
444
+ * @param {Number } options.opcode The opcode
445
+ * @param {Boolean } [options.readOnly=false] Specifies whether `data` can be
446
+ * modified
447
+ * @param {Boolean } [options.rsv1=false] Specifies whether or not to set the
448
+ * RSV1 bit
449
+ * @param {Function } [cb] Callback
450
+ * @private
451
+ */
452
+ getBlobData ( blob , compress , options , cb ) {
453
+ this . _bufferedBytes += options [ kByteLength ] ;
454
+ this . _state = GET_BLOB_DATA ;
455
+
456
+ blob
457
+ . arrayBuffer ( )
458
+ . then ( ( arrayBuffer ) => {
459
+ if ( this . _socket . destroyed ) {
460
+ const err = new Error (
461
+ 'The socket was closed while the blob was being read'
462
+ ) ;
463
+
464
+ this . callCallbacks ( err , cb ) ;
465
+ return ;
466
+ }
467
+
468
+ this . _bufferedBytes -= options [ kByteLength ] ;
469
+ const data = toBuffer ( arrayBuffer ) ;
470
+
471
+ if ( ! compress ) {
472
+ this . _state = DEFAULT ;
473
+ this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
474
+ this . dequeue ( ) ;
475
+ } else {
476
+ this . dispatch ( data , compress , options , cb ) ;
477
+ }
478
+ } )
479
+ . catch ( ( err ) => {
480
+ //
481
+ // `onError` is called in the next tick to not suppress the throwing
482
+ // behavior of the `'error'` event emitted by the `WebSocket` object.
483
+ //
484
+ process . nextTick ( onError , this , err , cb ) ;
485
+ } ) ;
486
+ }
487
+
394
488
/**
395
489
* Dispatches a message.
396
490
*
@@ -423,27 +517,19 @@ class Sender {
423
517
const perMessageDeflate = this . _extensions [ PerMessageDeflate . extensionName ] ;
424
518
425
519
this . _bufferedBytes += options [ kByteLength ] ;
426
- this . _deflating = true ;
520
+ this . _state = DEFLATING ;
427
521
perMessageDeflate . compress ( data , options . fin , ( _ , buf ) => {
428
522
if ( this . _socket . destroyed ) {
429
523
const err = new Error (
430
524
'The socket was closed while data was being compressed'
431
525
) ;
432
526
433
- if ( typeof cb === 'function' ) cb ( err ) ;
434
-
435
- for ( let i = 0 ; i < this . _queue . length ; i ++ ) {
436
- const params = this . _queue [ i ] ;
437
- const callback = params [ params . length - 1 ] ;
438
-
439
- if ( typeof callback === 'function' ) callback ( err ) ;
440
- }
441
-
527
+ this . callCallbacks ( err , cb ) ;
442
528
return ;
443
529
}
444
530
445
531
this . _bufferedBytes -= options [ kByteLength ] ;
446
- this . _deflating = false ;
532
+ this . _state = DEFAULT ;
447
533
options . readOnly = false ;
448
534
this . sendFrame ( Sender . frame ( buf , options ) , cb ) ;
449
535
this . dequeue ( ) ;
@@ -456,7 +542,7 @@ class Sender {
456
542
* @private
457
543
*/
458
544
dequeue ( ) {
459
- while ( ! this . _deflating && this . _queue . length ) {
545
+ while ( this . _state === DEFAULT && this . _queue . length ) {
460
546
const params = this . _queue . shift ( ) ;
461
547
462
548
this . _bufferedBytes -= params [ 3 ] [ kByteLength ] ;
@@ -495,3 +581,16 @@ class Sender {
495
581
}
496
582
497
583
module . exports = Sender ;
584
+
585
+ /**
586
+ * Handles a `Sender` error.
587
+ *
588
+ * @param {Sender } sender The `Sender` instance
589
+ * @param {Error } err The error
590
+ * @param {Function } [cb] The first pending callback
591
+ * @private
592
+ */
593
+ function onError ( sender , err , cb ) {
594
+ sender . callCallbacks ( err , cb ) ;
595
+ sender . onerror ( err ) ;
596
+ }
0 commit comments