serverless-spy 2.2.2 → 2.2.4
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/.jsii +3 -3
- package/common/SpyEventSender.ts +3 -1
- package/common/spyEvents/DynamoDBSpyEvent.ts +1 -1
- package/dist/releasetag.txt +1 -1
- package/extension/aws/UserFunction.js +0 -3
- package/lib/common/SpyEventSender.js +4 -2
- package/lib/common/SpyEventSender.mjs +4 -2
- package/lib/common/spyEvents/DynamoDBSpyEvent.d.ts +1 -1
- package/lib/common/spyEvents/DynamoDBSpyEvent.js +1 -1
- package/lib/common/spyEvents/DynamoDBSpyEvent.mjs +1 -1
- package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js +1 -1
- package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js.map +2 -2
- package/lib/src/ServerlessSpy.js +1 -1
- package/node_modules/ws/README.md +9 -10
- package/node_modules/ws/lib/constants.js +7 -1
- package/node_modules/ws/lib/receiver.js +11 -47
- package/node_modules/ws/lib/sender.js +172 -47
- package/node_modules/ws/lib/validation.js +22 -0
- package/node_modules/ws/lib/websocket-server.js +6 -5
- package/node_modules/ws/lib/websocket.js +71 -19
- package/node_modules/ws/package.json +4 -3
- package/package.json +3 -3
|
@@ -6,12 +6,19 @@ 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');
|
|
14
14
|
const maskBuffer = Buffer.alloc(4);
|
|
15
|
+
const RANDOM_POOL_SIZE = 8 * 1024;
|
|
16
|
+
let randomPool;
|
|
17
|
+
let randomPoolPointer = RANDOM_POOL_SIZE;
|
|
18
|
+
|
|
19
|
+
const DEFAULT = 0;
|
|
20
|
+
const DEFLATING = 1;
|
|
21
|
+
const GET_BLOB_DATA = 2;
|
|
15
22
|
|
|
16
23
|
/**
|
|
17
24
|
* HyBi Sender implementation.
|
|
@@ -39,8 +46,10 @@ class Sender {
|
|
|
39
46
|
this._compress = false;
|
|
40
47
|
|
|
41
48
|
this._bufferedBytes = 0;
|
|
42
|
-
this._deflating = false;
|
|
43
49
|
this._queue = [];
|
|
50
|
+
this._state = DEFAULT;
|
|
51
|
+
this.onerror = NOOP;
|
|
52
|
+
this[kWebSocket] = undefined;
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
/**
|
|
@@ -76,7 +85,24 @@ class Sender {
|
|
|
76
85
|
if (options.generateMask) {
|
|
77
86
|
options.generateMask(mask);
|
|
78
87
|
} else {
|
|
79
|
-
|
|
88
|
+
if (randomPoolPointer === RANDOM_POOL_SIZE) {
|
|
89
|
+
/* istanbul ignore else */
|
|
90
|
+
if (randomPool === undefined) {
|
|
91
|
+
//
|
|
92
|
+
// This is lazily initialized because server-sent frames must not
|
|
93
|
+
// be masked so it may never be used.
|
|
94
|
+
//
|
|
95
|
+
randomPool = Buffer.alloc(RANDOM_POOL_SIZE);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
|
|
99
|
+
randomPoolPointer = 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
mask[0] = randomPool[randomPoolPointer++];
|
|
103
|
+
mask[1] = randomPool[randomPoolPointer++];
|
|
104
|
+
mask[2] = randomPool[randomPoolPointer++];
|
|
105
|
+
mask[3] = randomPool[randomPoolPointer++];
|
|
80
106
|
}
|
|
81
107
|
|
|
82
108
|
skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
|
|
@@ -190,7 +216,7 @@ class Sender {
|
|
|
190
216
|
rsv1: false
|
|
191
217
|
};
|
|
192
218
|
|
|
193
|
-
if (this.
|
|
219
|
+
if (this._state !== DEFAULT) {
|
|
194
220
|
this.enqueue([this.dispatch, buf, false, options, cb]);
|
|
195
221
|
} else {
|
|
196
222
|
this.sendFrame(Sender.frame(buf, options), cb);
|
|
@@ -212,6 +238,9 @@ class Sender {
|
|
|
212
238
|
if (typeof data === 'string') {
|
|
213
239
|
byteLength = Buffer.byteLength(data);
|
|
214
240
|
readOnly = false;
|
|
241
|
+
} else if (isBlob(data)) {
|
|
242
|
+
byteLength = data.size;
|
|
243
|
+
readOnly = false;
|
|
215
244
|
} else {
|
|
216
245
|
data = toBuffer(data);
|
|
217
246
|
byteLength = data.length;
|
|
@@ -233,7 +262,13 @@ class Sender {
|
|
|
233
262
|
rsv1: false
|
|
234
263
|
};
|
|
235
264
|
|
|
236
|
-
if (
|
|
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) {
|
|
237
272
|
this.enqueue([this.dispatch, data, false, options, cb]);
|
|
238
273
|
} else {
|
|
239
274
|
this.sendFrame(Sender.frame(data, options), cb);
|
|
@@ -255,6 +290,9 @@ class Sender {
|
|
|
255
290
|
if (typeof data === 'string') {
|
|
256
291
|
byteLength = Buffer.byteLength(data);
|
|
257
292
|
readOnly = false;
|
|
293
|
+
} else if (isBlob(data)) {
|
|
294
|
+
byteLength = data.size;
|
|
295
|
+
readOnly = false;
|
|
258
296
|
} else {
|
|
259
297
|
data = toBuffer(data);
|
|
260
298
|
byteLength = data.length;
|
|
@@ -276,7 +314,13 @@ class Sender {
|
|
|
276
314
|
rsv1: false
|
|
277
315
|
};
|
|
278
316
|
|
|
279
|
-
if (
|
|
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) {
|
|
280
324
|
this.enqueue([this.dispatch, data, false, options, cb]);
|
|
281
325
|
} else {
|
|
282
326
|
this.sendFrame(Sender.frame(data, options), cb);
|
|
@@ -310,6 +354,9 @@ class Sender {
|
|
|
310
354
|
if (typeof data === 'string') {
|
|
311
355
|
byteLength = Buffer.byteLength(data);
|
|
312
356
|
readOnly = false;
|
|
357
|
+
} else if (isBlob(data)) {
|
|
358
|
+
byteLength = data.size;
|
|
359
|
+
readOnly = false;
|
|
313
360
|
} else {
|
|
314
361
|
data = toBuffer(data);
|
|
315
362
|
byteLength = data.length;
|
|
@@ -337,40 +384,94 @@ class Sender {
|
|
|
337
384
|
|
|
338
385
|
if (options.fin) this._firstFragment = true;
|
|
339
386
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
if (this.
|
|
353
|
-
this.enqueue([this.
|
|
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]);
|
|
354
401
|
} else {
|
|
355
|
-
this.
|
|
402
|
+
this.getBlobData(data, this._compress, opts, cb);
|
|
356
403
|
}
|
|
404
|
+
} else if (this._state !== DEFAULT) {
|
|
405
|
+
this.enqueue([this.dispatch, data, this._compress, opts, cb]);
|
|
357
406
|
} else {
|
|
358
|
-
this.
|
|
359
|
-
Sender.frame(data, {
|
|
360
|
-
[kByteLength]: byteLength,
|
|
361
|
-
fin: options.fin,
|
|
362
|
-
generateMask: this._generateMask,
|
|
363
|
-
mask: options.mask,
|
|
364
|
-
maskBuffer: this._maskBuffer,
|
|
365
|
-
opcode,
|
|
366
|
-
readOnly,
|
|
367
|
-
rsv1: false
|
|
368
|
-
}),
|
|
369
|
-
cb
|
|
370
|
-
);
|
|
407
|
+
this.dispatch(data, this._compress, opts, cb);
|
|
371
408
|
}
|
|
372
409
|
}
|
|
373
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Gets the contents of a blob as binary data.
|
|
413
|
+
*
|
|
414
|
+
* @param {Blob} blob The blob
|
|
415
|
+
* @param {Boolean} [compress=false] Specifies whether or not to compress
|
|
416
|
+
* the data
|
|
417
|
+
* @param {Object} options Options object
|
|
418
|
+
* @param {Boolean} [options.fin=false] Specifies whether or not to set the
|
|
419
|
+
* FIN bit
|
|
420
|
+
* @param {Function} [options.generateMask] The function used to generate the
|
|
421
|
+
* masking key
|
|
422
|
+
* @param {Boolean} [options.mask=false] Specifies whether or not to mask
|
|
423
|
+
* `data`
|
|
424
|
+
* @param {Buffer} [options.maskBuffer] The buffer used to store the masking
|
|
425
|
+
* key
|
|
426
|
+
* @param {Number} options.opcode The opcode
|
|
427
|
+
* @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
|
|
428
|
+
* modified
|
|
429
|
+
* @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
|
|
430
|
+
* RSV1 bit
|
|
431
|
+
* @param {Function} [cb] Callback
|
|
432
|
+
* @private
|
|
433
|
+
*/
|
|
434
|
+
getBlobData(blob, compress, options, cb) {
|
|
435
|
+
this._bufferedBytes += options[kByteLength];
|
|
436
|
+
this._state = GET_BLOB_DATA;
|
|
437
|
+
|
|
438
|
+
blob
|
|
439
|
+
.arrayBuffer()
|
|
440
|
+
.then((arrayBuffer) => {
|
|
441
|
+
if (this._socket.destroyed) {
|
|
442
|
+
const err = new Error(
|
|
443
|
+
'The socket was closed while the blob was being read'
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
//
|
|
447
|
+
// `callCallbacks` is called in the next tick to ensure that errors
|
|
448
|
+
// that might be thrown in the callbacks behave like errors thrown
|
|
449
|
+
// outside the promise chain.
|
|
450
|
+
//
|
|
451
|
+
process.nextTick(callCallbacks, this, err, cb);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
this._bufferedBytes -= options[kByteLength];
|
|
456
|
+
const data = toBuffer(arrayBuffer);
|
|
457
|
+
|
|
458
|
+
if (!compress) {
|
|
459
|
+
this._state = DEFAULT;
|
|
460
|
+
this.sendFrame(Sender.frame(data, options), cb);
|
|
461
|
+
this.dequeue();
|
|
462
|
+
} else {
|
|
463
|
+
this.dispatch(data, compress, options, cb);
|
|
464
|
+
}
|
|
465
|
+
})
|
|
466
|
+
.catch((err) => {
|
|
467
|
+
//
|
|
468
|
+
// `onError` is called in the next tick for the same reason that
|
|
469
|
+
// `callCallbacks` above is.
|
|
470
|
+
//
|
|
471
|
+
process.nextTick(onError, this, err, cb);
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
374
475
|
/**
|
|
375
476
|
* Dispatches a message.
|
|
376
477
|
*
|
|
@@ -403,27 +504,19 @@ class Sender {
|
|
|
403
504
|
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
|
|
404
505
|
|
|
405
506
|
this._bufferedBytes += options[kByteLength];
|
|
406
|
-
this.
|
|
507
|
+
this._state = DEFLATING;
|
|
407
508
|
perMessageDeflate.compress(data, options.fin, (_, buf) => {
|
|
408
509
|
if (this._socket.destroyed) {
|
|
409
510
|
const err = new Error(
|
|
410
511
|
'The socket was closed while data was being compressed'
|
|
411
512
|
);
|
|
412
513
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
for (let i = 0; i < this._queue.length; i++) {
|
|
416
|
-
const params = this._queue[i];
|
|
417
|
-
const callback = params[params.length - 1];
|
|
418
|
-
|
|
419
|
-
if (typeof callback === 'function') callback(err);
|
|
420
|
-
}
|
|
421
|
-
|
|
514
|
+
callCallbacks(this, err, cb);
|
|
422
515
|
return;
|
|
423
516
|
}
|
|
424
517
|
|
|
425
518
|
this._bufferedBytes -= options[kByteLength];
|
|
426
|
-
this.
|
|
519
|
+
this._state = DEFAULT;
|
|
427
520
|
options.readOnly = false;
|
|
428
521
|
this.sendFrame(Sender.frame(buf, options), cb);
|
|
429
522
|
this.dequeue();
|
|
@@ -436,7 +529,7 @@ class Sender {
|
|
|
436
529
|
* @private
|
|
437
530
|
*/
|
|
438
531
|
dequeue() {
|
|
439
|
-
while (
|
|
532
|
+
while (this._state === DEFAULT && this._queue.length) {
|
|
440
533
|
const params = this._queue.shift();
|
|
441
534
|
|
|
442
535
|
this._bufferedBytes -= params[3][kByteLength];
|
|
@@ -475,3 +568,35 @@ class Sender {
|
|
|
475
568
|
}
|
|
476
569
|
|
|
477
570
|
module.exports = Sender;
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Calls queued callbacks with an error.
|
|
574
|
+
*
|
|
575
|
+
* @param {Sender} sender The `Sender` instance
|
|
576
|
+
* @param {Error} err The error to call the callbacks with
|
|
577
|
+
* @param {Function} [cb] The first callback
|
|
578
|
+
* @private
|
|
579
|
+
*/
|
|
580
|
+
function callCallbacks(sender, err, cb) {
|
|
581
|
+
if (typeof cb === 'function') cb(err);
|
|
582
|
+
|
|
583
|
+
for (let i = 0; i < sender._queue.length; i++) {
|
|
584
|
+
const params = sender._queue[i];
|
|
585
|
+
const callback = params[params.length - 1];
|
|
586
|
+
|
|
587
|
+
if (typeof callback === 'function') callback(err);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Handles a `Sender` error.
|
|
593
|
+
*
|
|
594
|
+
* @param {Sender} sender The `Sender` instance
|
|
595
|
+
* @param {Error} err The error
|
|
596
|
+
* @param {Function} [cb] The first pending callback
|
|
597
|
+
* @private
|
|
598
|
+
*/
|
|
599
|
+
function onError(sender, err, cb) {
|
|
600
|
+
callCallbacks(sender, err, cb);
|
|
601
|
+
sender.onerror(err);
|
|
602
|
+
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { isUtf8 } = require('buffer');
|
|
4
4
|
|
|
5
|
+
const { hasBlob } = require('./constants');
|
|
6
|
+
|
|
5
7
|
//
|
|
6
8
|
// Allowed token characters:
|
|
7
9
|
//
|
|
@@ -107,7 +109,27 @@ function _isValidUTF8(buf) {
|
|
|
107
109
|
return true;
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Determines whether a value is a `Blob`.
|
|
114
|
+
*
|
|
115
|
+
* @param {*} value The value to be tested
|
|
116
|
+
* @return {Boolean} `true` if `value` is a `Blob`, else `false`
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
function isBlob(value) {
|
|
120
|
+
return (
|
|
121
|
+
hasBlob &&
|
|
122
|
+
typeof value === 'object' &&
|
|
123
|
+
typeof value.arrayBuffer === 'function' &&
|
|
124
|
+
typeof value.type === 'string' &&
|
|
125
|
+
typeof value.stream === 'function' &&
|
|
126
|
+
(value[Symbol.toStringTag] === 'Blob' ||
|
|
127
|
+
value[Symbol.toStringTag] === 'File')
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
110
131
|
module.exports = {
|
|
132
|
+
isBlob,
|
|
111
133
|
isValidStatusCode,
|
|
112
134
|
isValidUTF8: _isValidUTF8,
|
|
113
135
|
tokenChars
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */
|
|
1
|
+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -29,7 +29,7 @@ class WebSocketServer extends EventEmitter {
|
|
|
29
29
|
* Create a `WebSocketServer` instance.
|
|
30
30
|
*
|
|
31
31
|
* @param {Object} options Configuration options
|
|
32
|
-
* @param {Boolean} [options.allowSynchronousEvents=
|
|
32
|
+
* @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
|
|
33
33
|
* any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
|
|
34
34
|
* multiple times in the same tick
|
|
35
35
|
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
|
|
@@ -60,7 +60,7 @@ class WebSocketServer extends EventEmitter {
|
|
|
60
60
|
super();
|
|
61
61
|
|
|
62
62
|
options = {
|
|
63
|
-
allowSynchronousEvents:
|
|
63
|
+
allowSynchronousEvents: true,
|
|
64
64
|
autoPong: true,
|
|
65
65
|
maxPayload: 100 * 1024 * 1024,
|
|
66
66
|
skipUTF8Validation: false,
|
|
@@ -235,6 +235,7 @@ class WebSocketServer extends EventEmitter {
|
|
|
235
235
|
socket.on('error', socketOnError);
|
|
236
236
|
|
|
237
237
|
const key = req.headers['sec-websocket-key'];
|
|
238
|
+
const upgrade = req.headers.upgrade;
|
|
238
239
|
const version = +req.headers['sec-websocket-version'];
|
|
239
240
|
|
|
240
241
|
if (req.method !== 'GET') {
|
|
@@ -243,13 +244,13 @@ class WebSocketServer extends EventEmitter {
|
|
|
243
244
|
return;
|
|
244
245
|
}
|
|
245
246
|
|
|
246
|
-
if (
|
|
247
|
+
if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
|
|
247
248
|
const message = 'Invalid Upgrade header';
|
|
248
249
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
249
250
|
return;
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
if (
|
|
253
|
+
if (key === undefined || !keyRegex.test(key)) {
|
|
253
254
|
const message = 'Missing or invalid Sec-WebSocket-Key header';
|
|
254
255
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
255
256
|
return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$" }] */
|
|
1
|
+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$", "caughtErrors": "none" }] */
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
@@ -14,6 +14,8 @@ const { URL } = require('url');
|
|
|
14
14
|
const PerMessageDeflate = require('./permessage-deflate');
|
|
15
15
|
const Receiver = require('./receiver');
|
|
16
16
|
const Sender = require('./sender');
|
|
17
|
+
const { isBlob } = require('./validation');
|
|
18
|
+
|
|
17
19
|
const {
|
|
18
20
|
BINARY_TYPES,
|
|
19
21
|
EMPTY_BUFFER,
|
|
@@ -58,6 +60,7 @@ class WebSocket extends EventEmitter {
|
|
|
58
60
|
this._closeFrameSent = false;
|
|
59
61
|
this._closeMessage = EMPTY_BUFFER;
|
|
60
62
|
this._closeTimer = null;
|
|
63
|
+
this._errorEmitted = false;
|
|
61
64
|
this._extensions = {};
|
|
62
65
|
this._paused = false;
|
|
63
66
|
this._protocol = '';
|
|
@@ -90,9 +93,8 @@ class WebSocket extends EventEmitter {
|
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* type).
|
|
96
|
+
* For historical reasons, the custom "nodebuffer" type is used by the default
|
|
97
|
+
* instead of "blob".
|
|
96
98
|
*
|
|
97
99
|
* @type {String}
|
|
98
100
|
*/
|
|
@@ -213,11 +215,14 @@ class WebSocket extends EventEmitter {
|
|
|
213
215
|
skipUTF8Validation: options.skipUTF8Validation
|
|
214
216
|
});
|
|
215
217
|
|
|
216
|
-
|
|
218
|
+
const sender = new Sender(socket, this._extensions, options.generateMask);
|
|
219
|
+
|
|
217
220
|
this._receiver = receiver;
|
|
221
|
+
this._sender = sender;
|
|
218
222
|
this._socket = socket;
|
|
219
223
|
|
|
220
224
|
receiver[kWebSocket] = this;
|
|
225
|
+
sender[kWebSocket] = this;
|
|
221
226
|
socket[kWebSocket] = this;
|
|
222
227
|
|
|
223
228
|
receiver.on('conclude', receiverOnConclude);
|
|
@@ -227,6 +232,8 @@ class WebSocket extends EventEmitter {
|
|
|
227
232
|
receiver.on('ping', receiverOnPing);
|
|
228
233
|
receiver.on('pong', receiverOnPong);
|
|
229
234
|
|
|
235
|
+
sender.onerror = senderOnError;
|
|
236
|
+
|
|
230
237
|
//
|
|
231
238
|
// These methods may not be available if `socket` is just a `Duplex`.
|
|
232
239
|
//
|
|
@@ -322,13 +329,7 @@ class WebSocket extends EventEmitter {
|
|
|
322
329
|
}
|
|
323
330
|
});
|
|
324
331
|
|
|
325
|
-
|
|
326
|
-
// Specify a timeout for the closing handshake to complete.
|
|
327
|
-
//
|
|
328
|
-
this._closeTimer = setTimeout(
|
|
329
|
-
this._socket.destroy.bind(this._socket),
|
|
330
|
-
closeTimeout
|
|
331
|
-
);
|
|
332
|
+
setCloseTimer(this);
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
/**
|
|
@@ -623,7 +624,7 @@ module.exports = WebSocket;
|
|
|
623
624
|
* @param {(String|URL)} address The URL to which to connect
|
|
624
625
|
* @param {Array} protocols The subprotocols
|
|
625
626
|
* @param {Object} [options] Connection options
|
|
626
|
-
* @param {Boolean} [options.allowSynchronousEvents=
|
|
627
|
+
* @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any
|
|
627
628
|
* of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
|
|
628
629
|
* times in the same tick
|
|
629
630
|
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
|
|
@@ -652,7 +653,7 @@ module.exports = WebSocket;
|
|
|
652
653
|
*/
|
|
653
654
|
function initAsClient(websocket, address, protocols, options) {
|
|
654
655
|
const opts = {
|
|
655
|
-
allowSynchronousEvents:
|
|
656
|
+
allowSynchronousEvents: true,
|
|
656
657
|
autoPong: true,
|
|
657
658
|
protocolVersion: protocolVersions[1],
|
|
658
659
|
maxPayload: 100 * 1024 * 1024,
|
|
@@ -661,7 +662,6 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
661
662
|
followRedirects: false,
|
|
662
663
|
maxRedirects: 10,
|
|
663
664
|
...options,
|
|
664
|
-
createConnection: undefined,
|
|
665
665
|
socketPath: undefined,
|
|
666
666
|
hostname: undefined,
|
|
667
667
|
protocol: undefined,
|
|
@@ -732,7 +732,8 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
732
732
|
const protocolSet = new Set();
|
|
733
733
|
let perMessageDeflate;
|
|
734
734
|
|
|
735
|
-
opts.createConnection =
|
|
735
|
+
opts.createConnection =
|
|
736
|
+
opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
736
737
|
opts.defaultPort = opts.defaultPort || defaultPort;
|
|
737
738
|
opts.port = parsedUrl.port || defaultPort;
|
|
738
739
|
opts.host = parsedUrl.hostname.startsWith('[')
|
|
@@ -928,7 +929,9 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
928
929
|
|
|
929
930
|
req = websocket._req = null;
|
|
930
931
|
|
|
931
|
-
|
|
932
|
+
const upgrade = res.headers.upgrade;
|
|
933
|
+
|
|
934
|
+
if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
|
|
932
935
|
abortHandshake(websocket, socket, 'Invalid Upgrade header');
|
|
933
936
|
return;
|
|
934
937
|
}
|
|
@@ -1030,6 +1033,11 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
1030
1033
|
*/
|
|
1031
1034
|
function emitErrorAndClose(websocket, err) {
|
|
1032
1035
|
websocket._readyState = WebSocket.CLOSING;
|
|
1036
|
+
//
|
|
1037
|
+
// The following assignment is practically useless and is done only for
|
|
1038
|
+
// consistency.
|
|
1039
|
+
//
|
|
1040
|
+
websocket._errorEmitted = true;
|
|
1033
1041
|
websocket.emit('error', err);
|
|
1034
1042
|
websocket.emitClose();
|
|
1035
1043
|
}
|
|
@@ -1110,7 +1118,7 @@ function abortHandshake(websocket, stream, message) {
|
|
|
1110
1118
|
*/
|
|
1111
1119
|
function sendAfterClose(websocket, data, cb) {
|
|
1112
1120
|
if (data) {
|
|
1113
|
-
const length = toBuffer(data).length;
|
|
1121
|
+
const length = isBlob(data) ? data.size : toBuffer(data).length;
|
|
1114
1122
|
|
|
1115
1123
|
//
|
|
1116
1124
|
// The `_bufferedAmount` property is used only when the peer is a client and
|
|
@@ -1186,7 +1194,10 @@ function receiverOnError(err) {
|
|
|
1186
1194
|
websocket.close(err[kStatusCode]);
|
|
1187
1195
|
}
|
|
1188
1196
|
|
|
1189
|
-
websocket.
|
|
1197
|
+
if (!websocket._errorEmitted) {
|
|
1198
|
+
websocket._errorEmitted = true;
|
|
1199
|
+
websocket.emit('error', err);
|
|
1200
|
+
}
|
|
1190
1201
|
}
|
|
1191
1202
|
|
|
1192
1203
|
/**
|
|
@@ -1242,6 +1253,47 @@ function resume(stream) {
|
|
|
1242
1253
|
stream.resume();
|
|
1243
1254
|
}
|
|
1244
1255
|
|
|
1256
|
+
/**
|
|
1257
|
+
* The `Sender` error event handler.
|
|
1258
|
+
*
|
|
1259
|
+
* @param {Error} The error
|
|
1260
|
+
* @private
|
|
1261
|
+
*/
|
|
1262
|
+
function senderOnError(err) {
|
|
1263
|
+
const websocket = this[kWebSocket];
|
|
1264
|
+
|
|
1265
|
+
if (websocket.readyState === WebSocket.CLOSED) return;
|
|
1266
|
+
if (websocket.readyState === WebSocket.OPEN) {
|
|
1267
|
+
websocket._readyState = WebSocket.CLOSING;
|
|
1268
|
+
setCloseTimer(websocket);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
//
|
|
1272
|
+
// `socket.end()` is used instead of `socket.destroy()` to allow the other
|
|
1273
|
+
// peer to finish sending queued data. There is no need to set a timer here
|
|
1274
|
+
// because `CLOSING` means that it is already set or not needed.
|
|
1275
|
+
//
|
|
1276
|
+
this._socket.end();
|
|
1277
|
+
|
|
1278
|
+
if (!websocket._errorEmitted) {
|
|
1279
|
+
websocket._errorEmitted = true;
|
|
1280
|
+
websocket.emit('error', err);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* Set a timer to destroy the underlying raw socket of a WebSocket.
|
|
1286
|
+
*
|
|
1287
|
+
* @param {WebSocket} websocket The WebSocket instance
|
|
1288
|
+
* @private
|
|
1289
|
+
*/
|
|
1290
|
+
function setCloseTimer(websocket) {
|
|
1291
|
+
websocket._closeTimer = setTimeout(
|
|
1292
|
+
websocket._socket.destroy.bind(websocket._socket),
|
|
1293
|
+
closeTimeout
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1245
1297
|
/**
|
|
1246
1298
|
* The listener of the socket `'close'` event.
|
|
1247
1299
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ws",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.18.0",
|
|
4
4
|
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"HyBi",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"scripts": {
|
|
41
41
|
"test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js",
|
|
42
42
|
"integration": "mocha --throw-deprecation test/*.integration.js",
|
|
43
|
-
"lint": "eslint
|
|
43
|
+
"lint": "eslint . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\""
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"bufferutil": "^4.0.1",
|
|
@@ -57,9 +57,10 @@
|
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"benchmark": "^2.1.4",
|
|
59
59
|
"bufferutil": "^4.0.1",
|
|
60
|
-
"eslint": "^
|
|
60
|
+
"eslint": "^9.0.0",
|
|
61
61
|
"eslint-config-prettier": "^9.0.0",
|
|
62
62
|
"eslint-plugin-prettier": "^5.0.0",
|
|
63
|
+
"globals": "^15.0.0",
|
|
63
64
|
"mocha": "^8.4.0",
|
|
64
65
|
"nyc": "^15.0.0",
|
|
65
66
|
"prettier": "^3.0.0",
|
package/package.json
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@types/jest": "^29.5.11",
|
|
51
51
|
"@types/node": "^20.10.4",
|
|
52
52
|
"@types/uuid": "^9.0.7",
|
|
53
|
-
"@types/ws": "^8.5.
|
|
53
|
+
"@types/ws": "^8.5.12",
|
|
54
54
|
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
|
55
55
|
"@typescript-eslint/parser": "^6.12.0",
|
|
56
56
|
"aws-cdk-lib": "^2.124",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"json-format-highlight": "^1.0.4",
|
|
112
112
|
"open": "^9.1.0",
|
|
113
113
|
"serialize-error": "^11.0.3",
|
|
114
|
-
"ws": "^8.
|
|
114
|
+
"ws": "^8.17.1"
|
|
115
115
|
},
|
|
116
116
|
"keywords": [
|
|
117
117
|
"cdk",
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"require": "./lib/index.js"
|
|
137
137
|
},
|
|
138
138
|
"license": "MPL-2.0",
|
|
139
|
-
"version": "2.2.
|
|
139
|
+
"version": "2.2.4",
|
|
140
140
|
"types": "lib/index.d.ts",
|
|
141
141
|
"stability": "stable",
|
|
142
142
|
"jsii": {
|