@@ -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
/**
@@ -205,7 +211,7 @@ class Sender {
205
211
rsv1 : false
206
212
} ;
207
213
208
- if ( this . _deflating ) {
214
+ if ( this . _state !== DEFAULT ) {
209
215
this . enqueue ( [ this . dispatch , buf , false , options , cb ] ) ;
210
216
} else {
211
217
this . sendFrame ( Sender . frame ( buf , options ) , cb ) ;
@@ -227,6 +233,9 @@ class Sender {
227
233
if ( typeof data === 'string' ) {
228
234
byteLength = Buffer . byteLength ( data ) ;
229
235
readOnly = false ;
236
+ } else if ( isBlob ( data ) ) {
237
+ byteLength = data . size ;
238
+ readOnly = false ;
230
239
} else {
231
240
data = toBuffer ( data ) ;
232
241
byteLength = data . length ;
@@ -248,7 +257,13 @@ class Sender {
248
257
rsv1 : false
249
258
} ;
250
259
251
- if ( this . _deflating ) {
260
+ if ( isBlob ( data ) ) {
261
+ if ( this . _state !== DEFAULT ) {
262
+ this . enqueue ( [ this . getBlobData , data , false , options , cb ] ) ;
263
+ } else {
264
+ this . getBlobData ( data , false , options , cb ) ;
265
+ }
266
+ } else if ( this . _state !== DEFAULT ) {
252
267
this . enqueue ( [ this . dispatch , data , false , options , cb ] ) ;
253
268
} else {
254
269
this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
@@ -270,6 +285,9 @@ class Sender {
270
285
if ( typeof data === 'string' ) {
271
286
byteLength = Buffer . byteLength ( data ) ;
272
287
readOnly = false ;
288
+ } else if ( isBlob ( data ) ) {
289
+ byteLength = data . size ;
290
+ readOnly = false ;
273
291
} else {
274
292
data = toBuffer ( data ) ;
275
293
byteLength = data . length ;
@@ -291,7 +309,13 @@ class Sender {
291
309
rsv1 : false
292
310
} ;
293
311
294
- if ( this . _deflating ) {
312
+ if ( isBlob ( data ) ) {
313
+ if ( this . _state !== DEFAULT ) {
314
+ this . enqueue ( [ this . getBlobData , data , false , options , cb ] ) ;
315
+ } else {
316
+ this . getBlobData ( data , false , options , cb ) ;
317
+ }
318
+ } else if ( this . _state !== DEFAULT ) {
295
319
this . enqueue ( [ this . dispatch , data , false , options , cb ] ) ;
296
320
} else {
297
321
this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
@@ -325,6 +349,9 @@ class Sender {
325
349
if ( typeof data === 'string' ) {
326
350
byteLength = Buffer . byteLength ( data ) ;
327
351
readOnly = false ;
352
+ } else if ( isBlob ( data ) ) {
353
+ byteLength = data . size ;
354
+ readOnly = false ;
328
355
} else {
329
356
data = toBuffer ( data ) ;
330
357
byteLength = data . length ;
@@ -352,40 +379,107 @@ class Sender {
352
379
353
380
if ( options . fin ) this . _firstFragment = true ;
354
381
355
- if ( perMessageDeflate ) {
356
- const opts = {
357
- [ kByteLength ] : byteLength ,
358
- fin : options . fin ,
359
- generateMask : this . _generateMask ,
360
- mask : options . mask ,
361
- maskBuffer : this . _maskBuffer ,
362
- opcode ,
363
- readOnly ,
364
- rsv1
365
- } ;
366
-
367
- if ( this . _deflating ) {
368
- this . enqueue ( [ this . dispatch , data , this . _compress , opts , cb ] ) ;
382
+ const opts = {
383
+ [ kByteLength ] : byteLength ,
384
+ fin : options . fin ,
385
+ generateMask : this . _generateMask ,
386
+ mask : options . mask ,
387
+ maskBuffer : this . _maskBuffer ,
388
+ opcode ,
389
+ readOnly ,
390
+ rsv1
391
+ } ;
392
+
393
+ if ( isBlob ( data ) ) {
394
+ if ( this . _state !== DEFAULT ) {
395
+ this . enqueue ( [ this . getBlobData , data , this . _compress , opts , cb ] ) ;
369
396
} else {
370
- this . dispatch ( data , this . _compress , opts , cb ) ;
397
+ this . getBlobData ( data , this . _compress , opts , cb ) ;
371
398
}
399
+ } else if ( this . _state !== DEFAULT ) {
400
+ this . enqueue ( [ this . dispatch , data , this . _compress , opts , cb ] ) ;
372
401
} else {
373
- this . sendFrame (
374
- Sender . frame ( data , {
375
- [ kByteLength ] : byteLength ,
376
- fin : options . fin ,
377
- generateMask : this . _generateMask ,
378
- mask : options . mask ,
379
- maskBuffer : this . _maskBuffer ,
380
- opcode,
381
- readOnly,
382
- rsv1 : false
383
- } ) ,
384
- cb
385
- ) ;
402
+ this . dispatch ( data , this . _compress , opts , cb ) ;
386
403
}
387
404
}
388
405
406
+ /**
407
+ * Calls queued callbacks with an error.
408
+ *
409
+ * @param {Error } err The error to call the callbacks with
410
+ * @param {Function } [cb] The first callback
411
+ * @private
412
+ */
413
+ callCallbacks ( err , cb ) {
414
+ if ( typeof cb === 'function' ) cb ( err ) ;
415
+
416
+ for ( let i = 0 ; i < this . _queue . length ; i ++ ) {
417
+ const params = this . _queue [ i ] ;
418
+ const callback = params [ params . length - 1 ] ;
419
+
420
+ if ( typeof callback === 'function' ) callback ( err ) ;
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Gets the contents of a blob as binary data.
426
+ *
427
+ * @param {Blob } blob The blob
428
+ * @param {Boolean } [compress=false] Specifies whether or not to compress
429
+ * the data
430
+ * @param {Object } options Options object
431
+ * @param {Boolean } [options.fin=false] Specifies whether or not to set the
432
+ * FIN bit
433
+ * @param {Function } [options.generateMask] The function used to generate the
434
+ * masking key
435
+ * @param {Boolean } [options.mask=false] Specifies whether or not to mask
436
+ * `data`
437
+ * @param {Buffer } [options.maskBuffer] The buffer used to store the masking
438
+ * key
439
+ * @param {Number } options.opcode The opcode
440
+ * @param {Boolean } [options.readOnly=false] Specifies whether `data` can be
441
+ * modified
442
+ * @param {Boolean } [options.rsv1=false] Specifies whether or not to set the
443
+ * RSV1 bit
444
+ * @param {Function } [cb] Callback
445
+ * @private
446
+ */
447
+ getBlobData ( blob , compress , options , cb ) {
448
+ this . _bufferedBytes += options [ kByteLength ] ;
449
+ this . _state = GET_BLOB_DATA ;
450
+
451
+ blob
452
+ . arrayBuffer ( )
453
+ . then ( ( arrayBuffer ) => {
454
+ if ( this . _socket . destroyed ) {
455
+ const err = new Error (
456
+ 'The socket was closed while the blob was being read'
457
+ ) ;
458
+
459
+ this . callCallbacks ( err , cb ) ;
460
+ return ;
461
+ }
462
+
463
+ this . _bufferedBytes -= options [ kByteLength ] ;
464
+ const data = toBuffer ( arrayBuffer ) ;
465
+
466
+ if ( ! compress ) {
467
+ this . _state = DEFAULT ;
468
+ this . sendFrame ( Sender . frame ( data , options ) , cb ) ;
469
+ this . dequeue ( ) ;
470
+ } else {
471
+ this . dispatch ( data , compress , options , cb ) ;
472
+ }
473
+ } )
474
+ . catch ( ( err ) => {
475
+ //
476
+ // `onError` is called in the next tick to not suppress the throwing
477
+ // behavior of the `'error'` event emitted by the `WebSocket` object.
478
+ //
479
+ process . nextTick ( onError , this , err , cb ) ;
480
+ } ) ;
481
+ }
482
+
389
483
/**
390
484
* Dispatches a message.
391
485
*
@@ -418,27 +512,19 @@ class Sender {
418
512
const perMessageDeflate = this . _extensions [ PerMessageDeflate . extensionName ] ;
419
513
420
514
this . _bufferedBytes += options [ kByteLength ] ;
421
- this . _deflating = true ;
515
+ this . _state = DEFLATING ;
422
516
perMessageDeflate . compress ( data , options . fin , ( _ , buf ) => {
423
517
if ( this . _socket . destroyed ) {
424
518
const err = new Error (
425
519
'The socket was closed while data was being compressed'
426
520
) ;
427
521
428
- if ( typeof cb === 'function' ) cb ( err ) ;
429
-
430
- for ( let i = 0 ; i < this . _queue . length ; i ++ ) {
431
- const params = this . _queue [ i ] ;
432
- const callback = params [ params . length - 1 ] ;
433
-
434
- if ( typeof callback === 'function' ) callback ( err ) ;
435
- }
436
-
522
+ this . callCallbacks ( err , cb ) ;
437
523
return ;
438
524
}
439
525
440
526
this . _bufferedBytes -= options [ kByteLength ] ;
441
- this . _deflating = false ;
527
+ this . _state = DEFAULT ;
442
528
options . readOnly = false ;
443
529
this . sendFrame ( Sender . frame ( buf , options ) , cb ) ;
444
530
this . dequeue ( ) ;
@@ -451,7 +537,7 @@ class Sender {
451
537
* @private
452
538
*/
453
539
dequeue ( ) {
454
- while ( ! this . _deflating && this . _queue . length ) {
540
+ while ( this . _state === DEFAULT && this . _queue . length ) {
455
541
const params = this . _queue . shift ( ) ;
456
542
457
543
this . _bufferedBytes -= params [ 3 ] [ kByteLength ] ;
@@ -490,3 +576,16 @@ class Sender {
490
576
}
491
577
492
578
module . exports = Sender ;
579
+
580
+ /**
581
+ * Handles a `Sender` error.
582
+ *
583
+ * @param {Sender } sender The `Sender` instance
584
+ * @param {Error } err The error
585
+ * @param {Function } [cb] The first pending callback
586
+ * @private
587
+ */
588
+ function onError ( sender , err , cb ) {
589
+ sender . callCallbacks ( err , cb ) ;
590
+ sender . onerror ( err ) ;
591
+ }
0 commit comments