spawn-term 0.1.0 → 0.1.1

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.
Files changed (44) hide show
  1. package/assets/ink.cjs +30 -43
  2. package/assets/intl-adapter.cjs +1083 -0
  3. package/dist/cjs/components/App.cjs +4 -46
  4. package/dist/cjs/components/App.cjs.map +1 -1
  5. package/dist/cjs/components/ChildProcess.cjs +12 -54
  6. package/dist/cjs/components/ChildProcess.cjs.map +1 -1
  7. package/dist/cjs/components/Spinner.cjs +2 -3
  8. package/dist/cjs/components/Spinner.cjs.map +1 -1
  9. package/dist/cjs/createApp.cjs +4 -46
  10. package/dist/cjs/createApp.cjs.map +1 -1
  11. package/dist/cjs/index.cjs.cjs +16 -1
  12. package/dist/cjs/index.cjs.cjs.map +1 -1
  13. package/dist/cjs/index.esm.cjs +0 -2
  14. package/dist/cjs/index.esm.cjs.map +1 -1
  15. package/dist/cjs/ink.cjs +112 -0
  16. package/dist/cjs/ink.cjs.map +1 -0
  17. package/dist/cjs/types.cjs.map +1 -1
  18. package/dist/esm/components/App.mjs +1 -3
  19. package/dist/esm/components/App.mjs.map +1 -1
  20. package/dist/esm/components/ChildProcess.mjs +1 -3
  21. package/dist/esm/components/ChildProcess.mjs.map +1 -1
  22. package/dist/esm/components/Spinner.mjs +1 -3
  23. package/dist/esm/components/Spinner.mjs.map +1 -1
  24. package/dist/esm/createApp.mjs +3 -4
  25. package/dist/esm/createApp.mjs.map +1 -1
  26. package/dist/esm/index.cjs.mjs +12 -1
  27. package/dist/esm/index.cjs.mjs.map +1 -1
  28. package/dist/esm/index.esm.mjs +0 -2
  29. package/dist/esm/index.esm.mjs.map +1 -1
  30. package/dist/esm/ink.mjs +10 -0
  31. package/dist/esm/ink.mjs.map +1 -0
  32. package/dist/esm/types.mjs.map +1 -1
  33. package/dist/types/index.cjs.d.ts +4 -1
  34. package/dist/types/index.esm.d.ts +0 -2
  35. package/dist/types/ink.d.mts +15 -0
  36. package/dist/types/types.d.ts +1 -1
  37. package/package.json +3 -3
  38. package/assets/devtools.mjs +0 -4852
  39. package/assets/index.js +0 -10
  40. package/dist/cjs/lib/uuid.cjs +0 -27
  41. package/dist/cjs/lib/uuid.cjs.map +0 -1
  42. package/dist/esm/lib/uuid.mjs +0 -16
  43. package/dist/esm/lib/uuid.mjs.map +0 -1
  44. package/dist/types/lib/uuid.d.ts +0 -1
@@ -1,4852 +0,0 @@
1
- import require$$0$2 from 'stream';
2
- import require$$0 from 'zlib';
3
- import require$$0$1 from 'buffer';
4
- import require$$1 from 'crypto';
5
- import { g as getDefaultExportFromCjs } from './ink.cjs';
6
- import require$$0$3 from 'events';
7
- import require$$1$1 from 'https';
8
- import require$$2 from 'http';
9
- import require$$3 from 'net';
10
- import require$$4 from 'tls';
11
- import require$$7 from 'url';
12
- import devtools from 'react-devtools-core';
13
- import 'process';
14
- import 'react';
15
- import 'assert';
16
- import 'fs/promises';
17
- import 'module';
18
- import 'fs';
19
-
20
- var bufferUtil = {exports: {}};
21
-
22
- var constants;
23
- var hasRequiredConstants;
24
-
25
- function requireConstants () {
26
- if (hasRequiredConstants) return constants;
27
- hasRequiredConstants = 1;
28
-
29
- const BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];
30
- const hasBlob = typeof Blob !== 'undefined';
31
-
32
- if (hasBlob) BINARY_TYPES.push('blob');
33
-
34
- constants = {
35
- BINARY_TYPES,
36
- EMPTY_BUFFER: Buffer.alloc(0),
37
- GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
38
- hasBlob,
39
- kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),
40
- kListener: Symbol('kListener'),
41
- kStatusCode: Symbol('status-code'),
42
- kWebSocket: Symbol('websocket'),
43
- NOOP: () => {}
44
- };
45
- return constants;
46
- }
47
-
48
- var hasRequiredBufferUtil;
49
-
50
- function requireBufferUtil () {
51
- if (hasRequiredBufferUtil) return bufferUtil.exports;
52
- hasRequiredBufferUtil = 1;
53
-
54
- const { EMPTY_BUFFER } = requireConstants();
55
-
56
- const FastBuffer = Buffer[Symbol.species];
57
-
58
- /**
59
- * Merges an array of buffers into a new buffer.
60
- *
61
- * @param {Buffer[]} list The array of buffers to concat
62
- * @param {Number} totalLength The total length of buffers in the list
63
- * @return {Buffer} The resulting buffer
64
- * @public
65
- */
66
- function concat(list, totalLength) {
67
- if (list.length === 0) return EMPTY_BUFFER;
68
- if (list.length === 1) return list[0];
69
-
70
- const target = Buffer.allocUnsafe(totalLength);
71
- let offset = 0;
72
-
73
- for (let i = 0; i < list.length; i++) {
74
- const buf = list[i];
75
- target.set(buf, offset);
76
- offset += buf.length;
77
- }
78
-
79
- if (offset < totalLength) {
80
- return new FastBuffer(target.buffer, target.byteOffset, offset);
81
- }
82
-
83
- return target;
84
- }
85
-
86
- /**
87
- * Masks a buffer using the given mask.
88
- *
89
- * @param {Buffer} source The buffer to mask
90
- * @param {Buffer} mask The mask to use
91
- * @param {Buffer} output The buffer where to store the result
92
- * @param {Number} offset The offset at which to start writing
93
- * @param {Number} length The number of bytes to mask.
94
- * @public
95
- */
96
- function _mask(source, mask, output, offset, length) {
97
- for (let i = 0; i < length; i++) {
98
- output[offset + i] = source[i] ^ mask[i & 3];
99
- }
100
- }
101
-
102
- /**
103
- * Unmasks a buffer using the given mask.
104
- *
105
- * @param {Buffer} buffer The buffer to unmask
106
- * @param {Buffer} mask The mask to use
107
- * @public
108
- */
109
- function _unmask(buffer, mask) {
110
- for (let i = 0; i < buffer.length; i++) {
111
- buffer[i] ^= mask[i & 3];
112
- }
113
- }
114
-
115
- /**
116
- * Converts a buffer to an `ArrayBuffer`.
117
- *
118
- * @param {Buffer} buf The buffer to convert
119
- * @return {ArrayBuffer} Converted buffer
120
- * @public
121
- */
122
- function toArrayBuffer(buf) {
123
- if (buf.length === buf.buffer.byteLength) {
124
- return buf.buffer;
125
- }
126
-
127
- return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
128
- }
129
-
130
- /**
131
- * Converts `data` to a `Buffer`.
132
- *
133
- * @param {*} data The data to convert
134
- * @return {Buffer} The buffer
135
- * @throws {TypeError}
136
- * @public
137
- */
138
- function toBuffer(data) {
139
- toBuffer.readOnly = true;
140
-
141
- if (Buffer.isBuffer(data)) return data;
142
-
143
- let buf;
144
-
145
- if (data instanceof ArrayBuffer) {
146
- buf = new FastBuffer(data);
147
- } else if (ArrayBuffer.isView(data)) {
148
- buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);
149
- } else {
150
- buf = Buffer.from(data);
151
- toBuffer.readOnly = false;
152
- }
153
-
154
- return buf;
155
- }
156
-
157
- bufferUtil.exports = {
158
- concat,
159
- mask: _mask,
160
- toArrayBuffer,
161
- toBuffer,
162
- unmask: _unmask
163
- };
164
-
165
- /* istanbul ignore else */
166
- if (!process.env.WS_NO_BUFFER_UTIL) {
167
- try {
168
- const bufferUtil$1 = require('bufferutil');
169
-
170
- bufferUtil.exports.mask = function (source, mask, output, offset, length) {
171
- if (length < 48) _mask(source, mask, output, offset, length);
172
- else bufferUtil$1.mask(source, mask, output, offset, length);
173
- };
174
-
175
- bufferUtil.exports.unmask = function (buffer, mask) {
176
- if (buffer.length < 32) _unmask(buffer, mask);
177
- else bufferUtil$1.unmask(buffer, mask);
178
- };
179
- } catch (e) {
180
- // Continue regardless of the error.
181
- }
182
- }
183
- return bufferUtil.exports;
184
- }
185
-
186
- var limiter;
187
- var hasRequiredLimiter;
188
-
189
- function requireLimiter () {
190
- if (hasRequiredLimiter) return limiter;
191
- hasRequiredLimiter = 1;
192
-
193
- const kDone = Symbol('kDone');
194
- const kRun = Symbol('kRun');
195
-
196
- /**
197
- * A very simple job queue with adjustable concurrency. Adapted from
198
- * https://github.com/STRML/async-limiter
199
- */
200
- class Limiter {
201
- /**
202
- * Creates a new `Limiter`.
203
- *
204
- * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
205
- * to run concurrently
206
- */
207
- constructor(concurrency) {
208
- this[kDone] = () => {
209
- this.pending--;
210
- this[kRun]();
211
- };
212
- this.concurrency = concurrency || Infinity;
213
- this.jobs = [];
214
- this.pending = 0;
215
- }
216
-
217
- /**
218
- * Adds a job to the queue.
219
- *
220
- * @param {Function} job The job to run
221
- * @public
222
- */
223
- add(job) {
224
- this.jobs.push(job);
225
- this[kRun]();
226
- }
227
-
228
- /**
229
- * Removes a job from the queue and runs it if possible.
230
- *
231
- * @private
232
- */
233
- [kRun]() {
234
- if (this.pending === this.concurrency) return;
235
-
236
- if (this.jobs.length) {
237
- const job = this.jobs.shift();
238
-
239
- this.pending++;
240
- job(this[kDone]);
241
- }
242
- }
243
- }
244
-
245
- limiter = Limiter;
246
- return limiter;
247
- }
248
-
249
- var permessageDeflate;
250
- var hasRequiredPermessageDeflate;
251
-
252
- function requirePermessageDeflate () {
253
- if (hasRequiredPermessageDeflate) return permessageDeflate;
254
- hasRequiredPermessageDeflate = 1;
255
-
256
- const zlib = require$$0;
257
-
258
- const bufferUtil = requireBufferUtil();
259
- const Limiter = requireLimiter();
260
- const { kStatusCode } = requireConstants();
261
-
262
- const FastBuffer = Buffer[Symbol.species];
263
- const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
264
- const kPerMessageDeflate = Symbol('permessage-deflate');
265
- const kTotalLength = Symbol('total-length');
266
- const kCallback = Symbol('callback');
267
- const kBuffers = Symbol('buffers');
268
- const kError = Symbol('error');
269
-
270
- //
271
- // We limit zlib concurrency, which prevents severe memory fragmentation
272
- // as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
273
- // and https://github.com/websockets/ws/issues/1202
274
- //
275
- // Intentionally global; it's the global thread pool that's an issue.
276
- //
277
- let zlibLimiter;
278
-
279
- /**
280
- * permessage-deflate implementation.
281
- */
282
- class PerMessageDeflate {
283
- /**
284
- * Creates a PerMessageDeflate instance.
285
- *
286
- * @param {Object} [options] Configuration options
287
- * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
288
- * for, or request, a custom client window size
289
- * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
290
- * acknowledge disabling of client context takeover
291
- * @param {Number} [options.concurrencyLimit=10] The number of concurrent
292
- * calls to zlib
293
- * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
294
- * use of a custom server window size
295
- * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
296
- * disabling of server context takeover
297
- * @param {Number} [options.threshold=1024] Size (in bytes) below which
298
- * messages should not be compressed if context takeover is disabled
299
- * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
300
- * deflate
301
- * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
302
- * inflate
303
- * @param {Boolean} [isServer=false] Create the instance in either server or
304
- * client mode
305
- * @param {Number} [maxPayload=0] The maximum allowed message length
306
- */
307
- constructor(options, isServer, maxPayload) {
308
- this._maxPayload = maxPayload | 0;
309
- this._options = options || {};
310
- this._threshold =
311
- this._options.threshold !== undefined ? this._options.threshold : 1024;
312
- this._isServer = !!isServer;
313
- this._deflate = null;
314
- this._inflate = null;
315
-
316
- this.params = null;
317
-
318
- if (!zlibLimiter) {
319
- const concurrency =
320
- this._options.concurrencyLimit !== undefined
321
- ? this._options.concurrencyLimit
322
- : 10;
323
- zlibLimiter = new Limiter(concurrency);
324
- }
325
- }
326
-
327
- /**
328
- * @type {String}
329
- */
330
- static get extensionName() {
331
- return 'permessage-deflate';
332
- }
333
-
334
- /**
335
- * Create an extension negotiation offer.
336
- *
337
- * @return {Object} Extension parameters
338
- * @public
339
- */
340
- offer() {
341
- const params = {};
342
-
343
- if (this._options.serverNoContextTakeover) {
344
- params.server_no_context_takeover = true;
345
- }
346
- if (this._options.clientNoContextTakeover) {
347
- params.client_no_context_takeover = true;
348
- }
349
- if (this._options.serverMaxWindowBits) {
350
- params.server_max_window_bits = this._options.serverMaxWindowBits;
351
- }
352
- if (this._options.clientMaxWindowBits) {
353
- params.client_max_window_bits = this._options.clientMaxWindowBits;
354
- } else if (this._options.clientMaxWindowBits == null) {
355
- params.client_max_window_bits = true;
356
- }
357
-
358
- return params;
359
- }
360
-
361
- /**
362
- * Accept an extension negotiation offer/response.
363
- *
364
- * @param {Array} configurations The extension negotiation offers/reponse
365
- * @return {Object} Accepted configuration
366
- * @public
367
- */
368
- accept(configurations) {
369
- configurations = this.normalizeParams(configurations);
370
-
371
- this.params = this._isServer
372
- ? this.acceptAsServer(configurations)
373
- : this.acceptAsClient(configurations);
374
-
375
- return this.params;
376
- }
377
-
378
- /**
379
- * Releases all resources used by the extension.
380
- *
381
- * @public
382
- */
383
- cleanup() {
384
- if (this._inflate) {
385
- this._inflate.close();
386
- this._inflate = null;
387
- }
388
-
389
- if (this._deflate) {
390
- const callback = this._deflate[kCallback];
391
-
392
- this._deflate.close();
393
- this._deflate = null;
394
-
395
- if (callback) {
396
- callback(
397
- new Error(
398
- 'The deflate stream was closed while data was being processed'
399
- )
400
- );
401
- }
402
- }
403
- }
404
-
405
- /**
406
- * Accept an extension negotiation offer.
407
- *
408
- * @param {Array} offers The extension negotiation offers
409
- * @return {Object} Accepted configuration
410
- * @private
411
- */
412
- acceptAsServer(offers) {
413
- const opts = this._options;
414
- const accepted = offers.find((params) => {
415
- if (
416
- (opts.serverNoContextTakeover === false &&
417
- params.server_no_context_takeover) ||
418
- (params.server_max_window_bits &&
419
- (opts.serverMaxWindowBits === false ||
420
- (typeof opts.serverMaxWindowBits === 'number' &&
421
- opts.serverMaxWindowBits > params.server_max_window_bits))) ||
422
- (typeof opts.clientMaxWindowBits === 'number' &&
423
- !params.client_max_window_bits)
424
- ) {
425
- return false;
426
- }
427
-
428
- return true;
429
- });
430
-
431
- if (!accepted) {
432
- throw new Error('None of the extension offers can be accepted');
433
- }
434
-
435
- if (opts.serverNoContextTakeover) {
436
- accepted.server_no_context_takeover = true;
437
- }
438
- if (opts.clientNoContextTakeover) {
439
- accepted.client_no_context_takeover = true;
440
- }
441
- if (typeof opts.serverMaxWindowBits === 'number') {
442
- accepted.server_max_window_bits = opts.serverMaxWindowBits;
443
- }
444
- if (typeof opts.clientMaxWindowBits === 'number') {
445
- accepted.client_max_window_bits = opts.clientMaxWindowBits;
446
- } else if (
447
- accepted.client_max_window_bits === true ||
448
- opts.clientMaxWindowBits === false
449
- ) {
450
- delete accepted.client_max_window_bits;
451
- }
452
-
453
- return accepted;
454
- }
455
-
456
- /**
457
- * Accept the extension negotiation response.
458
- *
459
- * @param {Array} response The extension negotiation response
460
- * @return {Object} Accepted configuration
461
- * @private
462
- */
463
- acceptAsClient(response) {
464
- const params = response[0];
465
-
466
- if (
467
- this._options.clientNoContextTakeover === false &&
468
- params.client_no_context_takeover
469
- ) {
470
- throw new Error('Unexpected parameter "client_no_context_takeover"');
471
- }
472
-
473
- if (!params.client_max_window_bits) {
474
- if (typeof this._options.clientMaxWindowBits === 'number') {
475
- params.client_max_window_bits = this._options.clientMaxWindowBits;
476
- }
477
- } else if (
478
- this._options.clientMaxWindowBits === false ||
479
- (typeof this._options.clientMaxWindowBits === 'number' &&
480
- params.client_max_window_bits > this._options.clientMaxWindowBits)
481
- ) {
482
- throw new Error(
483
- 'Unexpected or invalid parameter "client_max_window_bits"'
484
- );
485
- }
486
-
487
- return params;
488
- }
489
-
490
- /**
491
- * Normalize parameters.
492
- *
493
- * @param {Array} configurations The extension negotiation offers/reponse
494
- * @return {Array} The offers/response with normalized parameters
495
- * @private
496
- */
497
- normalizeParams(configurations) {
498
- configurations.forEach((params) => {
499
- Object.keys(params).forEach((key) => {
500
- let value = params[key];
501
-
502
- if (value.length > 1) {
503
- throw new Error(`Parameter "${key}" must have only a single value`);
504
- }
505
-
506
- value = value[0];
507
-
508
- if (key === 'client_max_window_bits') {
509
- if (value !== true) {
510
- const num = +value;
511
- if (!Number.isInteger(num) || num < 8 || num > 15) {
512
- throw new TypeError(
513
- `Invalid value for parameter "${key}": ${value}`
514
- );
515
- }
516
- value = num;
517
- } else if (!this._isServer) {
518
- throw new TypeError(
519
- `Invalid value for parameter "${key}": ${value}`
520
- );
521
- }
522
- } else if (key === 'server_max_window_bits') {
523
- const num = +value;
524
- if (!Number.isInteger(num) || num < 8 || num > 15) {
525
- throw new TypeError(
526
- `Invalid value for parameter "${key}": ${value}`
527
- );
528
- }
529
- value = num;
530
- } else if (
531
- key === 'client_no_context_takeover' ||
532
- key === 'server_no_context_takeover'
533
- ) {
534
- if (value !== true) {
535
- throw new TypeError(
536
- `Invalid value for parameter "${key}": ${value}`
537
- );
538
- }
539
- } else {
540
- throw new Error(`Unknown parameter "${key}"`);
541
- }
542
-
543
- params[key] = value;
544
- });
545
- });
546
-
547
- return configurations;
548
- }
549
-
550
- /**
551
- * Decompress data. Concurrency limited.
552
- *
553
- * @param {Buffer} data Compressed data
554
- * @param {Boolean} fin Specifies whether or not this is the last fragment
555
- * @param {Function} callback Callback
556
- * @public
557
- */
558
- decompress(data, fin, callback) {
559
- zlibLimiter.add((done) => {
560
- this._decompress(data, fin, (err, result) => {
561
- done();
562
- callback(err, result);
563
- });
564
- });
565
- }
566
-
567
- /**
568
- * Compress data. Concurrency limited.
569
- *
570
- * @param {(Buffer|String)} data Data to compress
571
- * @param {Boolean} fin Specifies whether or not this is the last fragment
572
- * @param {Function} callback Callback
573
- * @public
574
- */
575
- compress(data, fin, callback) {
576
- zlibLimiter.add((done) => {
577
- this._compress(data, fin, (err, result) => {
578
- done();
579
- callback(err, result);
580
- });
581
- });
582
- }
583
-
584
- /**
585
- * Decompress data.
586
- *
587
- * @param {Buffer} data Compressed data
588
- * @param {Boolean} fin Specifies whether or not this is the last fragment
589
- * @param {Function} callback Callback
590
- * @private
591
- */
592
- _decompress(data, fin, callback) {
593
- const endpoint = this._isServer ? 'client' : 'server';
594
-
595
- if (!this._inflate) {
596
- const key = `${endpoint}_max_window_bits`;
597
- const windowBits =
598
- typeof this.params[key] !== 'number'
599
- ? zlib.Z_DEFAULT_WINDOWBITS
600
- : this.params[key];
601
-
602
- this._inflate = zlib.createInflateRaw({
603
- ...this._options.zlibInflateOptions,
604
- windowBits
605
- });
606
- this._inflate[kPerMessageDeflate] = this;
607
- this._inflate[kTotalLength] = 0;
608
- this._inflate[kBuffers] = [];
609
- this._inflate.on('error', inflateOnError);
610
- this._inflate.on('data', inflateOnData);
611
- }
612
-
613
- this._inflate[kCallback] = callback;
614
-
615
- this._inflate.write(data);
616
- if (fin) this._inflate.write(TRAILER);
617
-
618
- this._inflate.flush(() => {
619
- const err = this._inflate[kError];
620
-
621
- if (err) {
622
- this._inflate.close();
623
- this._inflate = null;
624
- callback(err);
625
- return;
626
- }
627
-
628
- const data = bufferUtil.concat(
629
- this._inflate[kBuffers],
630
- this._inflate[kTotalLength]
631
- );
632
-
633
- if (this._inflate._readableState.endEmitted) {
634
- this._inflate.close();
635
- this._inflate = null;
636
- } else {
637
- this._inflate[kTotalLength] = 0;
638
- this._inflate[kBuffers] = [];
639
-
640
- if (fin && this.params[`${endpoint}_no_context_takeover`]) {
641
- this._inflate.reset();
642
- }
643
- }
644
-
645
- callback(null, data);
646
- });
647
- }
648
-
649
- /**
650
- * Compress data.
651
- *
652
- * @param {(Buffer|String)} data Data to compress
653
- * @param {Boolean} fin Specifies whether or not this is the last fragment
654
- * @param {Function} callback Callback
655
- * @private
656
- */
657
- _compress(data, fin, callback) {
658
- const endpoint = this._isServer ? 'server' : 'client';
659
-
660
- if (!this._deflate) {
661
- const key = `${endpoint}_max_window_bits`;
662
- const windowBits =
663
- typeof this.params[key] !== 'number'
664
- ? zlib.Z_DEFAULT_WINDOWBITS
665
- : this.params[key];
666
-
667
- this._deflate = zlib.createDeflateRaw({
668
- ...this._options.zlibDeflateOptions,
669
- windowBits
670
- });
671
-
672
- this._deflate[kTotalLength] = 0;
673
- this._deflate[kBuffers] = [];
674
-
675
- this._deflate.on('data', deflateOnData);
676
- }
677
-
678
- this._deflate[kCallback] = callback;
679
-
680
- this._deflate.write(data);
681
- this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
682
- if (!this._deflate) {
683
- //
684
- // The deflate stream was closed while data was being processed.
685
- //
686
- return;
687
- }
688
-
689
- let data = bufferUtil.concat(
690
- this._deflate[kBuffers],
691
- this._deflate[kTotalLength]
692
- );
693
-
694
- if (fin) {
695
- data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
696
- }
697
-
698
- //
699
- // Ensure that the callback will not be called again in
700
- // `PerMessageDeflate#cleanup()`.
701
- //
702
- this._deflate[kCallback] = null;
703
-
704
- this._deflate[kTotalLength] = 0;
705
- this._deflate[kBuffers] = [];
706
-
707
- if (fin && this.params[`${endpoint}_no_context_takeover`]) {
708
- this._deflate.reset();
709
- }
710
-
711
- callback(null, data);
712
- });
713
- }
714
- }
715
-
716
- permessageDeflate = PerMessageDeflate;
717
-
718
- /**
719
- * The listener of the `zlib.DeflateRaw` stream `'data'` event.
720
- *
721
- * @param {Buffer} chunk A chunk of data
722
- * @private
723
- */
724
- function deflateOnData(chunk) {
725
- this[kBuffers].push(chunk);
726
- this[kTotalLength] += chunk.length;
727
- }
728
-
729
- /**
730
- * The listener of the `zlib.InflateRaw` stream `'data'` event.
731
- *
732
- * @param {Buffer} chunk A chunk of data
733
- * @private
734
- */
735
- function inflateOnData(chunk) {
736
- this[kTotalLength] += chunk.length;
737
-
738
- if (
739
- this[kPerMessageDeflate]._maxPayload < 1 ||
740
- this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
741
- ) {
742
- this[kBuffers].push(chunk);
743
- return;
744
- }
745
-
746
- this[kError] = new RangeError('Max payload size exceeded');
747
- this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
748
- this[kError][kStatusCode] = 1009;
749
- this.removeListener('data', inflateOnData);
750
- this.reset();
751
- }
752
-
753
- /**
754
- * The listener of the `zlib.InflateRaw` stream `'error'` event.
755
- *
756
- * @param {Error} err The emitted error
757
- * @private
758
- */
759
- function inflateOnError(err) {
760
- //
761
- // There is no need to call `Zlib#close()` as the handle is automatically
762
- // closed when an error is emitted.
763
- //
764
- this[kPerMessageDeflate]._inflate = null;
765
- err[kStatusCode] = 1007;
766
- this[kCallback](err);
767
- }
768
- return permessageDeflate;
769
- }
770
-
771
- var validation = {exports: {}};
772
-
773
- var hasRequiredValidation;
774
-
775
- function requireValidation () {
776
- if (hasRequiredValidation) return validation.exports;
777
- hasRequiredValidation = 1;
778
-
779
- const { isUtf8 } = require$$0$1;
780
-
781
- const { hasBlob } = requireConstants();
782
-
783
- //
784
- // Allowed token characters:
785
- //
786
- // '!', '#', '$', '%', '&', ''', '*', '+', '-',
787
- // '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
788
- //
789
- // tokenChars[32] === 0 // ' '
790
- // tokenChars[33] === 1 // '!'
791
- // tokenChars[34] === 0 // '"'
792
- // ...
793
- //
794
- // prettier-ignore
795
- const tokenChars = [
796
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
797
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
798
- 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
799
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
800
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
801
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
802
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
803
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
804
- ];
805
-
806
- /**
807
- * Checks if a status code is allowed in a close frame.
808
- *
809
- * @param {Number} code The status code
810
- * @return {Boolean} `true` if the status code is valid, else `false`
811
- * @public
812
- */
813
- function isValidStatusCode(code) {
814
- return (
815
- (code >= 1000 &&
816
- code <= 1014 &&
817
- code !== 1004 &&
818
- code !== 1005 &&
819
- code !== 1006) ||
820
- (code >= 3000 && code <= 4999)
821
- );
822
- }
823
-
824
- /**
825
- * Checks if a given buffer contains only correct UTF-8.
826
- * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
827
- * Markus Kuhn.
828
- *
829
- * @param {Buffer} buf The buffer to check
830
- * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
831
- * @public
832
- */
833
- function _isValidUTF8(buf) {
834
- const len = buf.length;
835
- let i = 0;
836
-
837
- while (i < len) {
838
- if ((buf[i] & 0x80) === 0) {
839
- // 0xxxxxxx
840
- i++;
841
- } else if ((buf[i] & 0xe0) === 0xc0) {
842
- // 110xxxxx 10xxxxxx
843
- if (
844
- i + 1 === len ||
845
- (buf[i + 1] & 0xc0) !== 0x80 ||
846
- (buf[i] & 0xfe) === 0xc0 // Overlong
847
- ) {
848
- return false;
849
- }
850
-
851
- i += 2;
852
- } else if ((buf[i] & 0xf0) === 0xe0) {
853
- // 1110xxxx 10xxxxxx 10xxxxxx
854
- if (
855
- i + 2 >= len ||
856
- (buf[i + 1] & 0xc0) !== 0x80 ||
857
- (buf[i + 2] & 0xc0) !== 0x80 ||
858
- (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong
859
- (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)
860
- ) {
861
- return false;
862
- }
863
-
864
- i += 3;
865
- } else if ((buf[i] & 0xf8) === 0xf0) {
866
- // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
867
- if (
868
- i + 3 >= len ||
869
- (buf[i + 1] & 0xc0) !== 0x80 ||
870
- (buf[i + 2] & 0xc0) !== 0x80 ||
871
- (buf[i + 3] & 0xc0) !== 0x80 ||
872
- (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong
873
- (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||
874
- buf[i] > 0xf4 // > U+10FFFF
875
- ) {
876
- return false;
877
- }
878
-
879
- i += 4;
880
- } else {
881
- return false;
882
- }
883
- }
884
-
885
- return true;
886
- }
887
-
888
- /**
889
- * Determines whether a value is a `Blob`.
890
- *
891
- * @param {*} value The value to be tested
892
- * @return {Boolean} `true` if `value` is a `Blob`, else `false`
893
- * @private
894
- */
895
- function isBlob(value) {
896
- return (
897
- hasBlob &&
898
- typeof value === 'object' &&
899
- typeof value.arrayBuffer === 'function' &&
900
- typeof value.type === 'string' &&
901
- typeof value.stream === 'function' &&
902
- (value[Symbol.toStringTag] === 'Blob' ||
903
- value[Symbol.toStringTag] === 'File')
904
- );
905
- }
906
-
907
- validation.exports = {
908
- isBlob,
909
- isValidStatusCode,
910
- isValidUTF8: _isValidUTF8,
911
- tokenChars
912
- };
913
-
914
- if (isUtf8) {
915
- validation.exports.isValidUTF8 = function (buf) {
916
- return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);
917
- };
918
- } /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {
919
- try {
920
- const isValidUTF8 = require('utf-8-validate');
921
-
922
- validation.exports.isValidUTF8 = function (buf) {
923
- return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
924
- };
925
- } catch (e) {
926
- // Continue regardless of the error.
927
- }
928
- }
929
- return validation.exports;
930
- }
931
-
932
- var receiver;
933
- var hasRequiredReceiver;
934
-
935
- function requireReceiver () {
936
- if (hasRequiredReceiver) return receiver;
937
- hasRequiredReceiver = 1;
938
-
939
- const { Writable } = require$$0$2;
940
-
941
- const PerMessageDeflate = requirePermessageDeflate();
942
- const {
943
- BINARY_TYPES,
944
- EMPTY_BUFFER,
945
- kStatusCode,
946
- kWebSocket
947
- } = requireConstants();
948
- const { concat, toArrayBuffer, unmask } = requireBufferUtil();
949
- const { isValidStatusCode, isValidUTF8 } = requireValidation();
950
-
951
- const FastBuffer = Buffer[Symbol.species];
952
-
953
- const GET_INFO = 0;
954
- const GET_PAYLOAD_LENGTH_16 = 1;
955
- const GET_PAYLOAD_LENGTH_64 = 2;
956
- const GET_MASK = 3;
957
- const GET_DATA = 4;
958
- const INFLATING = 5;
959
- const DEFER_EVENT = 6;
960
-
961
- /**
962
- * HyBi Receiver implementation.
963
- *
964
- * @extends Writable
965
- */
966
- class Receiver extends Writable {
967
- /**
968
- * Creates a Receiver instance.
969
- *
970
- * @param {Object} [options] Options object
971
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
972
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
973
- * multiple times in the same tick
974
- * @param {String} [options.binaryType=nodebuffer] The type for binary data
975
- * @param {Object} [options.extensions] An object containing the negotiated
976
- * extensions
977
- * @param {Boolean} [options.isServer=false] Specifies whether to operate in
978
- * client or server mode
979
- * @param {Number} [options.maxPayload=0] The maximum allowed message length
980
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
981
- * not to skip UTF-8 validation for text and close messages
982
- */
983
- constructor(options = {}) {
984
- super();
985
-
986
- this._allowSynchronousEvents =
987
- options.allowSynchronousEvents !== undefined
988
- ? options.allowSynchronousEvents
989
- : true;
990
- this._binaryType = options.binaryType || BINARY_TYPES[0];
991
- this._extensions = options.extensions || {};
992
- this._isServer = !!options.isServer;
993
- this._maxPayload = options.maxPayload | 0;
994
- this._skipUTF8Validation = !!options.skipUTF8Validation;
995
- this[kWebSocket] = undefined;
996
-
997
- this._bufferedBytes = 0;
998
- this._buffers = [];
999
-
1000
- this._compressed = false;
1001
- this._payloadLength = 0;
1002
- this._mask = undefined;
1003
- this._fragmented = 0;
1004
- this._masked = false;
1005
- this._fin = false;
1006
- this._opcode = 0;
1007
-
1008
- this._totalPayloadLength = 0;
1009
- this._messageLength = 0;
1010
- this._fragments = [];
1011
-
1012
- this._errored = false;
1013
- this._loop = false;
1014
- this._state = GET_INFO;
1015
- }
1016
-
1017
- /**
1018
- * Implements `Writable.prototype._write()`.
1019
- *
1020
- * @param {Buffer} chunk The chunk of data to write
1021
- * @param {String} encoding The character encoding of `chunk`
1022
- * @param {Function} cb Callback
1023
- * @private
1024
- */
1025
- _write(chunk, encoding, cb) {
1026
- if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
1027
-
1028
- this._bufferedBytes += chunk.length;
1029
- this._buffers.push(chunk);
1030
- this.startLoop(cb);
1031
- }
1032
-
1033
- /**
1034
- * Consumes `n` bytes from the buffered data.
1035
- *
1036
- * @param {Number} n The number of bytes to consume
1037
- * @return {Buffer} The consumed bytes
1038
- * @private
1039
- */
1040
- consume(n) {
1041
- this._bufferedBytes -= n;
1042
-
1043
- if (n === this._buffers[0].length) return this._buffers.shift();
1044
-
1045
- if (n < this._buffers[0].length) {
1046
- const buf = this._buffers[0];
1047
- this._buffers[0] = new FastBuffer(
1048
- buf.buffer,
1049
- buf.byteOffset + n,
1050
- buf.length - n
1051
- );
1052
-
1053
- return new FastBuffer(buf.buffer, buf.byteOffset, n);
1054
- }
1055
-
1056
- const dst = Buffer.allocUnsafe(n);
1057
-
1058
- do {
1059
- const buf = this._buffers[0];
1060
- const offset = dst.length - n;
1061
-
1062
- if (n >= buf.length) {
1063
- dst.set(this._buffers.shift(), offset);
1064
- } else {
1065
- dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
1066
- this._buffers[0] = new FastBuffer(
1067
- buf.buffer,
1068
- buf.byteOffset + n,
1069
- buf.length - n
1070
- );
1071
- }
1072
-
1073
- n -= buf.length;
1074
- } while (n > 0);
1075
-
1076
- return dst;
1077
- }
1078
-
1079
- /**
1080
- * Starts the parsing loop.
1081
- *
1082
- * @param {Function} cb Callback
1083
- * @private
1084
- */
1085
- startLoop(cb) {
1086
- this._loop = true;
1087
-
1088
- do {
1089
- switch (this._state) {
1090
- case GET_INFO:
1091
- this.getInfo(cb);
1092
- break;
1093
- case GET_PAYLOAD_LENGTH_16:
1094
- this.getPayloadLength16(cb);
1095
- break;
1096
- case GET_PAYLOAD_LENGTH_64:
1097
- this.getPayloadLength64(cb);
1098
- break;
1099
- case GET_MASK:
1100
- this.getMask();
1101
- break;
1102
- case GET_DATA:
1103
- this.getData(cb);
1104
- break;
1105
- case INFLATING:
1106
- case DEFER_EVENT:
1107
- this._loop = false;
1108
- return;
1109
- }
1110
- } while (this._loop);
1111
-
1112
- if (!this._errored) cb();
1113
- }
1114
-
1115
- /**
1116
- * Reads the first two bytes of a frame.
1117
- *
1118
- * @param {Function} cb Callback
1119
- * @private
1120
- */
1121
- getInfo(cb) {
1122
- if (this._bufferedBytes < 2) {
1123
- this._loop = false;
1124
- return;
1125
- }
1126
-
1127
- const buf = this.consume(2);
1128
-
1129
- if ((buf[0] & 0x30) !== 0x00) {
1130
- const error = this.createError(
1131
- RangeError,
1132
- 'RSV2 and RSV3 must be clear',
1133
- true,
1134
- 1002,
1135
- 'WS_ERR_UNEXPECTED_RSV_2_3'
1136
- );
1137
-
1138
- cb(error);
1139
- return;
1140
- }
1141
-
1142
- const compressed = (buf[0] & 0x40) === 0x40;
1143
-
1144
- if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
1145
- const error = this.createError(
1146
- RangeError,
1147
- 'RSV1 must be clear',
1148
- true,
1149
- 1002,
1150
- 'WS_ERR_UNEXPECTED_RSV_1'
1151
- );
1152
-
1153
- cb(error);
1154
- return;
1155
- }
1156
-
1157
- this._fin = (buf[0] & 0x80) === 0x80;
1158
- this._opcode = buf[0] & 0x0f;
1159
- this._payloadLength = buf[1] & 0x7f;
1160
-
1161
- if (this._opcode === 0x00) {
1162
- if (compressed) {
1163
- const error = this.createError(
1164
- RangeError,
1165
- 'RSV1 must be clear',
1166
- true,
1167
- 1002,
1168
- 'WS_ERR_UNEXPECTED_RSV_1'
1169
- );
1170
-
1171
- cb(error);
1172
- return;
1173
- }
1174
-
1175
- if (!this._fragmented) {
1176
- const error = this.createError(
1177
- RangeError,
1178
- 'invalid opcode 0',
1179
- true,
1180
- 1002,
1181
- 'WS_ERR_INVALID_OPCODE'
1182
- );
1183
-
1184
- cb(error);
1185
- return;
1186
- }
1187
-
1188
- this._opcode = this._fragmented;
1189
- } else if (this._opcode === 0x01 || this._opcode === 0x02) {
1190
- if (this._fragmented) {
1191
- const error = this.createError(
1192
- RangeError,
1193
- `invalid opcode ${this._opcode}`,
1194
- true,
1195
- 1002,
1196
- 'WS_ERR_INVALID_OPCODE'
1197
- );
1198
-
1199
- cb(error);
1200
- return;
1201
- }
1202
-
1203
- this._compressed = compressed;
1204
- } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
1205
- if (!this._fin) {
1206
- const error = this.createError(
1207
- RangeError,
1208
- 'FIN must be set',
1209
- true,
1210
- 1002,
1211
- 'WS_ERR_EXPECTED_FIN'
1212
- );
1213
-
1214
- cb(error);
1215
- return;
1216
- }
1217
-
1218
- if (compressed) {
1219
- const error = this.createError(
1220
- RangeError,
1221
- 'RSV1 must be clear',
1222
- true,
1223
- 1002,
1224
- 'WS_ERR_UNEXPECTED_RSV_1'
1225
- );
1226
-
1227
- cb(error);
1228
- return;
1229
- }
1230
-
1231
- if (
1232
- this._payloadLength > 0x7d ||
1233
- (this._opcode === 0x08 && this._payloadLength === 1)
1234
- ) {
1235
- const error = this.createError(
1236
- RangeError,
1237
- `invalid payload length ${this._payloadLength}`,
1238
- true,
1239
- 1002,
1240
- 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
1241
- );
1242
-
1243
- cb(error);
1244
- return;
1245
- }
1246
- } else {
1247
- const error = this.createError(
1248
- RangeError,
1249
- `invalid opcode ${this._opcode}`,
1250
- true,
1251
- 1002,
1252
- 'WS_ERR_INVALID_OPCODE'
1253
- );
1254
-
1255
- cb(error);
1256
- return;
1257
- }
1258
-
1259
- if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
1260
- this._masked = (buf[1] & 0x80) === 0x80;
1261
-
1262
- if (this._isServer) {
1263
- if (!this._masked) {
1264
- const error = this.createError(
1265
- RangeError,
1266
- 'MASK must be set',
1267
- true,
1268
- 1002,
1269
- 'WS_ERR_EXPECTED_MASK'
1270
- );
1271
-
1272
- cb(error);
1273
- return;
1274
- }
1275
- } else if (this._masked) {
1276
- const error = this.createError(
1277
- RangeError,
1278
- 'MASK must be clear',
1279
- true,
1280
- 1002,
1281
- 'WS_ERR_UNEXPECTED_MASK'
1282
- );
1283
-
1284
- cb(error);
1285
- return;
1286
- }
1287
-
1288
- if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
1289
- else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
1290
- else this.haveLength(cb);
1291
- }
1292
-
1293
- /**
1294
- * Gets extended payload length (7+16).
1295
- *
1296
- * @param {Function} cb Callback
1297
- * @private
1298
- */
1299
- getPayloadLength16(cb) {
1300
- if (this._bufferedBytes < 2) {
1301
- this._loop = false;
1302
- return;
1303
- }
1304
-
1305
- this._payloadLength = this.consume(2).readUInt16BE(0);
1306
- this.haveLength(cb);
1307
- }
1308
-
1309
- /**
1310
- * Gets extended payload length (7+64).
1311
- *
1312
- * @param {Function} cb Callback
1313
- * @private
1314
- */
1315
- getPayloadLength64(cb) {
1316
- if (this._bufferedBytes < 8) {
1317
- this._loop = false;
1318
- return;
1319
- }
1320
-
1321
- const buf = this.consume(8);
1322
- const num = buf.readUInt32BE(0);
1323
-
1324
- //
1325
- // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
1326
- // if payload length is greater than this number.
1327
- //
1328
- if (num > Math.pow(2, 53 - 32) - 1) {
1329
- const error = this.createError(
1330
- RangeError,
1331
- 'Unsupported WebSocket frame: payload length > 2^53 - 1',
1332
- false,
1333
- 1009,
1334
- 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
1335
- );
1336
-
1337
- cb(error);
1338
- return;
1339
- }
1340
-
1341
- this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
1342
- this.haveLength(cb);
1343
- }
1344
-
1345
- /**
1346
- * Payload length has been read.
1347
- *
1348
- * @param {Function} cb Callback
1349
- * @private
1350
- */
1351
- haveLength(cb) {
1352
- if (this._payloadLength && this._opcode < 0x08) {
1353
- this._totalPayloadLength += this._payloadLength;
1354
- if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
1355
- const error = this.createError(
1356
- RangeError,
1357
- 'Max payload size exceeded',
1358
- false,
1359
- 1009,
1360
- 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
1361
- );
1362
-
1363
- cb(error);
1364
- return;
1365
- }
1366
- }
1367
-
1368
- if (this._masked) this._state = GET_MASK;
1369
- else this._state = GET_DATA;
1370
- }
1371
-
1372
- /**
1373
- * Reads mask bytes.
1374
- *
1375
- * @private
1376
- */
1377
- getMask() {
1378
- if (this._bufferedBytes < 4) {
1379
- this._loop = false;
1380
- return;
1381
- }
1382
-
1383
- this._mask = this.consume(4);
1384
- this._state = GET_DATA;
1385
- }
1386
-
1387
- /**
1388
- * Reads data bytes.
1389
- *
1390
- * @param {Function} cb Callback
1391
- * @private
1392
- */
1393
- getData(cb) {
1394
- let data = EMPTY_BUFFER;
1395
-
1396
- if (this._payloadLength) {
1397
- if (this._bufferedBytes < this._payloadLength) {
1398
- this._loop = false;
1399
- return;
1400
- }
1401
-
1402
- data = this.consume(this._payloadLength);
1403
-
1404
- if (
1405
- this._masked &&
1406
- (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0
1407
- ) {
1408
- unmask(data, this._mask);
1409
- }
1410
- }
1411
-
1412
- if (this._opcode > 0x07) {
1413
- this.controlMessage(data, cb);
1414
- return;
1415
- }
1416
-
1417
- if (this._compressed) {
1418
- this._state = INFLATING;
1419
- this.decompress(data, cb);
1420
- return;
1421
- }
1422
-
1423
- if (data.length) {
1424
- //
1425
- // This message is not compressed so its length is the sum of the payload
1426
- // length of all fragments.
1427
- //
1428
- this._messageLength = this._totalPayloadLength;
1429
- this._fragments.push(data);
1430
- }
1431
-
1432
- this.dataMessage(cb);
1433
- }
1434
-
1435
- /**
1436
- * Decompresses data.
1437
- *
1438
- * @param {Buffer} data Compressed data
1439
- * @param {Function} cb Callback
1440
- * @private
1441
- */
1442
- decompress(data, cb) {
1443
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
1444
-
1445
- perMessageDeflate.decompress(data, this._fin, (err, buf) => {
1446
- if (err) return cb(err);
1447
-
1448
- if (buf.length) {
1449
- this._messageLength += buf.length;
1450
- if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
1451
- const error = this.createError(
1452
- RangeError,
1453
- 'Max payload size exceeded',
1454
- false,
1455
- 1009,
1456
- 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
1457
- );
1458
-
1459
- cb(error);
1460
- return;
1461
- }
1462
-
1463
- this._fragments.push(buf);
1464
- }
1465
-
1466
- this.dataMessage(cb);
1467
- if (this._state === GET_INFO) this.startLoop(cb);
1468
- });
1469
- }
1470
-
1471
- /**
1472
- * Handles a data message.
1473
- *
1474
- * @param {Function} cb Callback
1475
- * @private
1476
- */
1477
- dataMessage(cb) {
1478
- if (!this._fin) {
1479
- this._state = GET_INFO;
1480
- return;
1481
- }
1482
-
1483
- const messageLength = this._messageLength;
1484
- const fragments = this._fragments;
1485
-
1486
- this._totalPayloadLength = 0;
1487
- this._messageLength = 0;
1488
- this._fragmented = 0;
1489
- this._fragments = [];
1490
-
1491
- if (this._opcode === 2) {
1492
- let data;
1493
-
1494
- if (this._binaryType === 'nodebuffer') {
1495
- data = concat(fragments, messageLength);
1496
- } else if (this._binaryType === 'arraybuffer') {
1497
- data = toArrayBuffer(concat(fragments, messageLength));
1498
- } else if (this._binaryType === 'blob') {
1499
- data = new Blob(fragments);
1500
- } else {
1501
- data = fragments;
1502
- }
1503
-
1504
- if (this._allowSynchronousEvents) {
1505
- this.emit('message', data, true);
1506
- this._state = GET_INFO;
1507
- } else {
1508
- this._state = DEFER_EVENT;
1509
- setImmediate(() => {
1510
- this.emit('message', data, true);
1511
- this._state = GET_INFO;
1512
- this.startLoop(cb);
1513
- });
1514
- }
1515
- } else {
1516
- const buf = concat(fragments, messageLength);
1517
-
1518
- if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
1519
- const error = this.createError(
1520
- Error,
1521
- 'invalid UTF-8 sequence',
1522
- true,
1523
- 1007,
1524
- 'WS_ERR_INVALID_UTF8'
1525
- );
1526
-
1527
- cb(error);
1528
- return;
1529
- }
1530
-
1531
- if (this._state === INFLATING || this._allowSynchronousEvents) {
1532
- this.emit('message', buf, false);
1533
- this._state = GET_INFO;
1534
- } else {
1535
- this._state = DEFER_EVENT;
1536
- setImmediate(() => {
1537
- this.emit('message', buf, false);
1538
- this._state = GET_INFO;
1539
- this.startLoop(cb);
1540
- });
1541
- }
1542
- }
1543
- }
1544
-
1545
- /**
1546
- * Handles a control message.
1547
- *
1548
- * @param {Buffer} data Data to handle
1549
- * @return {(Error|RangeError|undefined)} A possible error
1550
- * @private
1551
- */
1552
- controlMessage(data, cb) {
1553
- if (this._opcode === 0x08) {
1554
- if (data.length === 0) {
1555
- this._loop = false;
1556
- this.emit('conclude', 1005, EMPTY_BUFFER);
1557
- this.end();
1558
- } else {
1559
- const code = data.readUInt16BE(0);
1560
-
1561
- if (!isValidStatusCode(code)) {
1562
- const error = this.createError(
1563
- RangeError,
1564
- `invalid status code ${code}`,
1565
- true,
1566
- 1002,
1567
- 'WS_ERR_INVALID_CLOSE_CODE'
1568
- );
1569
-
1570
- cb(error);
1571
- return;
1572
- }
1573
-
1574
- const buf = new FastBuffer(
1575
- data.buffer,
1576
- data.byteOffset + 2,
1577
- data.length - 2
1578
- );
1579
-
1580
- if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
1581
- const error = this.createError(
1582
- Error,
1583
- 'invalid UTF-8 sequence',
1584
- true,
1585
- 1007,
1586
- 'WS_ERR_INVALID_UTF8'
1587
- );
1588
-
1589
- cb(error);
1590
- return;
1591
- }
1592
-
1593
- this._loop = false;
1594
- this.emit('conclude', code, buf);
1595
- this.end();
1596
- }
1597
-
1598
- this._state = GET_INFO;
1599
- return;
1600
- }
1601
-
1602
- if (this._allowSynchronousEvents) {
1603
- this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);
1604
- this._state = GET_INFO;
1605
- } else {
1606
- this._state = DEFER_EVENT;
1607
- setImmediate(() => {
1608
- this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);
1609
- this._state = GET_INFO;
1610
- this.startLoop(cb);
1611
- });
1612
- }
1613
- }
1614
-
1615
- /**
1616
- * Builds an error object.
1617
- *
1618
- * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
1619
- * @param {String} message The error message
1620
- * @param {Boolean} prefix Specifies whether or not to add a default prefix to
1621
- * `message`
1622
- * @param {Number} statusCode The status code
1623
- * @param {String} errorCode The exposed error code
1624
- * @return {(Error|RangeError)} The error
1625
- * @private
1626
- */
1627
- createError(ErrorCtor, message, prefix, statusCode, errorCode) {
1628
- this._loop = false;
1629
- this._errored = true;
1630
-
1631
- const err = new ErrorCtor(
1632
- prefix ? `Invalid WebSocket frame: ${message}` : message
1633
- );
1634
-
1635
- Error.captureStackTrace(err, this.createError);
1636
- err.code = errorCode;
1637
- err[kStatusCode] = statusCode;
1638
- return err;
1639
- }
1640
- }
1641
-
1642
- receiver = Receiver;
1643
- return receiver;
1644
- }
1645
-
1646
- requireReceiver();
1647
-
1648
- /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */
1649
-
1650
- var sender;
1651
- var hasRequiredSender;
1652
-
1653
- function requireSender () {
1654
- if (hasRequiredSender) return sender;
1655
- hasRequiredSender = 1;
1656
- const { randomFillSync } = require$$1;
1657
-
1658
- const PerMessageDeflate = requirePermessageDeflate();
1659
- const { EMPTY_BUFFER, kWebSocket, NOOP } = requireConstants();
1660
- const { isBlob, isValidStatusCode } = requireValidation();
1661
- const { mask: applyMask, toBuffer } = requireBufferUtil();
1662
-
1663
- const kByteLength = Symbol('kByteLength');
1664
- const maskBuffer = Buffer.alloc(4);
1665
- const RANDOM_POOL_SIZE = 8 * 1024;
1666
- let randomPool;
1667
- let randomPoolPointer = RANDOM_POOL_SIZE;
1668
-
1669
- const DEFAULT = 0;
1670
- const DEFLATING = 1;
1671
- const GET_BLOB_DATA = 2;
1672
-
1673
- /**
1674
- * HyBi Sender implementation.
1675
- */
1676
- class Sender {
1677
- /**
1678
- * Creates a Sender instance.
1679
- *
1680
- * @param {Duplex} socket The connection socket
1681
- * @param {Object} [extensions] An object containing the negotiated extensions
1682
- * @param {Function} [generateMask] The function used to generate the masking
1683
- * key
1684
- */
1685
- constructor(socket, extensions, generateMask) {
1686
- this._extensions = extensions || {};
1687
-
1688
- if (generateMask) {
1689
- this._generateMask = generateMask;
1690
- this._maskBuffer = Buffer.alloc(4);
1691
- }
1692
-
1693
- this._socket = socket;
1694
-
1695
- this._firstFragment = true;
1696
- this._compress = false;
1697
-
1698
- this._bufferedBytes = 0;
1699
- this._queue = [];
1700
- this._state = DEFAULT;
1701
- this.onerror = NOOP;
1702
- this[kWebSocket] = undefined;
1703
- }
1704
-
1705
- /**
1706
- * Frames a piece of data according to the HyBi WebSocket protocol.
1707
- *
1708
- * @param {(Buffer|String)} data The data to frame
1709
- * @param {Object} options Options object
1710
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1711
- * FIN bit
1712
- * @param {Function} [options.generateMask] The function used to generate the
1713
- * masking key
1714
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1715
- * `data`
1716
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1717
- * key
1718
- * @param {Number} options.opcode The opcode
1719
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1720
- * modified
1721
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1722
- * RSV1 bit
1723
- * @return {(Buffer|String)[]} The framed data
1724
- * @public
1725
- */
1726
- static frame(data, options) {
1727
- let mask;
1728
- let merge = false;
1729
- let offset = 2;
1730
- let skipMasking = false;
1731
-
1732
- if (options.mask) {
1733
- mask = options.maskBuffer || maskBuffer;
1734
-
1735
- if (options.generateMask) {
1736
- options.generateMask(mask);
1737
- } else {
1738
- if (randomPoolPointer === RANDOM_POOL_SIZE) {
1739
- /* istanbul ignore else */
1740
- if (randomPool === undefined) {
1741
- //
1742
- // This is lazily initialized because server-sent frames must not
1743
- // be masked so it may never be used.
1744
- //
1745
- randomPool = Buffer.alloc(RANDOM_POOL_SIZE);
1746
- }
1747
-
1748
- randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
1749
- randomPoolPointer = 0;
1750
- }
1751
-
1752
- mask[0] = randomPool[randomPoolPointer++];
1753
- mask[1] = randomPool[randomPoolPointer++];
1754
- mask[2] = randomPool[randomPoolPointer++];
1755
- mask[3] = randomPool[randomPoolPointer++];
1756
- }
1757
-
1758
- skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
1759
- offset = 6;
1760
- }
1761
-
1762
- let dataLength;
1763
-
1764
- if (typeof data === 'string') {
1765
- if (
1766
- (!options.mask || skipMasking) &&
1767
- options[kByteLength] !== undefined
1768
- ) {
1769
- dataLength = options[kByteLength];
1770
- } else {
1771
- data = Buffer.from(data);
1772
- dataLength = data.length;
1773
- }
1774
- } else {
1775
- dataLength = data.length;
1776
- merge = options.mask && options.readOnly && !skipMasking;
1777
- }
1778
-
1779
- let payloadLength = dataLength;
1780
-
1781
- if (dataLength >= 65536) {
1782
- offset += 8;
1783
- payloadLength = 127;
1784
- } else if (dataLength > 125) {
1785
- offset += 2;
1786
- payloadLength = 126;
1787
- }
1788
-
1789
- const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);
1790
-
1791
- target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
1792
- if (options.rsv1) target[0] |= 0x40;
1793
-
1794
- target[1] = payloadLength;
1795
-
1796
- if (payloadLength === 126) {
1797
- target.writeUInt16BE(dataLength, 2);
1798
- } else if (payloadLength === 127) {
1799
- target[2] = target[3] = 0;
1800
- target.writeUIntBE(dataLength, 4, 6);
1801
- }
1802
-
1803
- if (!options.mask) return [target, data];
1804
-
1805
- target[1] |= 0x80;
1806
- target[offset - 4] = mask[0];
1807
- target[offset - 3] = mask[1];
1808
- target[offset - 2] = mask[2];
1809
- target[offset - 1] = mask[3];
1810
-
1811
- if (skipMasking) return [target, data];
1812
-
1813
- if (merge) {
1814
- applyMask(data, mask, target, offset, dataLength);
1815
- return [target];
1816
- }
1817
-
1818
- applyMask(data, mask, data, 0, dataLength);
1819
- return [target, data];
1820
- }
1821
-
1822
- /**
1823
- * Sends a close message to the other peer.
1824
- *
1825
- * @param {Number} [code] The status code component of the body
1826
- * @param {(String|Buffer)} [data] The message component of the body
1827
- * @param {Boolean} [mask=false] Specifies whether or not to mask the message
1828
- * @param {Function} [cb] Callback
1829
- * @public
1830
- */
1831
- close(code, data, mask, cb) {
1832
- let buf;
1833
-
1834
- if (code === undefined) {
1835
- buf = EMPTY_BUFFER;
1836
- } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
1837
- throw new TypeError('First argument must be a valid error code number');
1838
- } else if (data === undefined || !data.length) {
1839
- buf = Buffer.allocUnsafe(2);
1840
- buf.writeUInt16BE(code, 0);
1841
- } else {
1842
- const length = Buffer.byteLength(data);
1843
-
1844
- if (length > 123) {
1845
- throw new RangeError('The message must not be greater than 123 bytes');
1846
- }
1847
-
1848
- buf = Buffer.allocUnsafe(2 + length);
1849
- buf.writeUInt16BE(code, 0);
1850
-
1851
- if (typeof data === 'string') {
1852
- buf.write(data, 2);
1853
- } else {
1854
- buf.set(data, 2);
1855
- }
1856
- }
1857
-
1858
- const options = {
1859
- [kByteLength]: buf.length,
1860
- fin: true,
1861
- generateMask: this._generateMask,
1862
- mask,
1863
- maskBuffer: this._maskBuffer,
1864
- opcode: 0x08,
1865
- readOnly: false,
1866
- rsv1: false
1867
- };
1868
-
1869
- if (this._state !== DEFAULT) {
1870
- this.enqueue([this.dispatch, buf, false, options, cb]);
1871
- } else {
1872
- this.sendFrame(Sender.frame(buf, options), cb);
1873
- }
1874
- }
1875
-
1876
- /**
1877
- * Sends a ping message to the other peer.
1878
- *
1879
- * @param {*} data The message to send
1880
- * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1881
- * @param {Function} [cb] Callback
1882
- * @public
1883
- */
1884
- ping(data, mask, cb) {
1885
- let byteLength;
1886
- let readOnly;
1887
-
1888
- if (typeof data === 'string') {
1889
- byteLength = Buffer.byteLength(data);
1890
- readOnly = false;
1891
- } else if (isBlob(data)) {
1892
- byteLength = data.size;
1893
- readOnly = false;
1894
- } else {
1895
- data = toBuffer(data);
1896
- byteLength = data.length;
1897
- readOnly = toBuffer.readOnly;
1898
- }
1899
-
1900
- if (byteLength > 125) {
1901
- throw new RangeError('The data size must not be greater than 125 bytes');
1902
- }
1903
-
1904
- const options = {
1905
- [kByteLength]: byteLength,
1906
- fin: true,
1907
- generateMask: this._generateMask,
1908
- mask,
1909
- maskBuffer: this._maskBuffer,
1910
- opcode: 0x09,
1911
- readOnly,
1912
- rsv1: false
1913
- };
1914
-
1915
- if (isBlob(data)) {
1916
- if (this._state !== DEFAULT) {
1917
- this.enqueue([this.getBlobData, data, false, options, cb]);
1918
- } else {
1919
- this.getBlobData(data, false, options, cb);
1920
- }
1921
- } else if (this._state !== DEFAULT) {
1922
- this.enqueue([this.dispatch, data, false, options, cb]);
1923
- } else {
1924
- this.sendFrame(Sender.frame(data, options), cb);
1925
- }
1926
- }
1927
-
1928
- /**
1929
- * Sends a pong message to the other peer.
1930
- *
1931
- * @param {*} data The message to send
1932
- * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1933
- * @param {Function} [cb] Callback
1934
- * @public
1935
- */
1936
- pong(data, mask, cb) {
1937
- let byteLength;
1938
- let readOnly;
1939
-
1940
- if (typeof data === 'string') {
1941
- byteLength = Buffer.byteLength(data);
1942
- readOnly = false;
1943
- } else if (isBlob(data)) {
1944
- byteLength = data.size;
1945
- readOnly = false;
1946
- } else {
1947
- data = toBuffer(data);
1948
- byteLength = data.length;
1949
- readOnly = toBuffer.readOnly;
1950
- }
1951
-
1952
- if (byteLength > 125) {
1953
- throw new RangeError('The data size must not be greater than 125 bytes');
1954
- }
1955
-
1956
- const options = {
1957
- [kByteLength]: byteLength,
1958
- fin: true,
1959
- generateMask: this._generateMask,
1960
- mask,
1961
- maskBuffer: this._maskBuffer,
1962
- opcode: 0x0a,
1963
- readOnly,
1964
- rsv1: false
1965
- };
1966
-
1967
- if (isBlob(data)) {
1968
- if (this._state !== DEFAULT) {
1969
- this.enqueue([this.getBlobData, data, false, options, cb]);
1970
- } else {
1971
- this.getBlobData(data, false, options, cb);
1972
- }
1973
- } else if (this._state !== DEFAULT) {
1974
- this.enqueue([this.dispatch, data, false, options, cb]);
1975
- } else {
1976
- this.sendFrame(Sender.frame(data, options), cb);
1977
- }
1978
- }
1979
-
1980
- /**
1981
- * Sends a data message to the other peer.
1982
- *
1983
- * @param {*} data The message to send
1984
- * @param {Object} options Options object
1985
- * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
1986
- * or text
1987
- * @param {Boolean} [options.compress=false] Specifies whether or not to
1988
- * compress `data`
1989
- * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
1990
- * last one
1991
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1992
- * `data`
1993
- * @param {Function} [cb] Callback
1994
- * @public
1995
- */
1996
- send(data, options, cb) {
1997
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
1998
- let opcode = options.binary ? 2 : 1;
1999
- let rsv1 = options.compress;
2000
-
2001
- let byteLength;
2002
- let readOnly;
2003
-
2004
- if (typeof data === 'string') {
2005
- byteLength = Buffer.byteLength(data);
2006
- readOnly = false;
2007
- } else if (isBlob(data)) {
2008
- byteLength = data.size;
2009
- readOnly = false;
2010
- } else {
2011
- data = toBuffer(data);
2012
- byteLength = data.length;
2013
- readOnly = toBuffer.readOnly;
2014
- }
2015
-
2016
- if (this._firstFragment) {
2017
- this._firstFragment = false;
2018
- if (
2019
- rsv1 &&
2020
- perMessageDeflate &&
2021
- perMessageDeflate.params[
2022
- perMessageDeflate._isServer
2023
- ? 'server_no_context_takeover'
2024
- : 'client_no_context_takeover'
2025
- ]
2026
- ) {
2027
- rsv1 = byteLength >= perMessageDeflate._threshold;
2028
- }
2029
- this._compress = rsv1;
2030
- } else {
2031
- rsv1 = false;
2032
- opcode = 0;
2033
- }
2034
-
2035
- if (options.fin) this._firstFragment = true;
2036
-
2037
- const opts = {
2038
- [kByteLength]: byteLength,
2039
- fin: options.fin,
2040
- generateMask: this._generateMask,
2041
- mask: options.mask,
2042
- maskBuffer: this._maskBuffer,
2043
- opcode,
2044
- readOnly,
2045
- rsv1
2046
- };
2047
-
2048
- if (isBlob(data)) {
2049
- if (this._state !== DEFAULT) {
2050
- this.enqueue([this.getBlobData, data, this._compress, opts, cb]);
2051
- } else {
2052
- this.getBlobData(data, this._compress, opts, cb);
2053
- }
2054
- } else if (this._state !== DEFAULT) {
2055
- this.enqueue([this.dispatch, data, this._compress, opts, cb]);
2056
- } else {
2057
- this.dispatch(data, this._compress, opts, cb);
2058
- }
2059
- }
2060
-
2061
- /**
2062
- * Gets the contents of a blob as binary data.
2063
- *
2064
- * @param {Blob} blob The blob
2065
- * @param {Boolean} [compress=false] Specifies whether or not to compress
2066
- * the data
2067
- * @param {Object} options Options object
2068
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
2069
- * FIN bit
2070
- * @param {Function} [options.generateMask] The function used to generate the
2071
- * masking key
2072
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
2073
- * `data`
2074
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
2075
- * key
2076
- * @param {Number} options.opcode The opcode
2077
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
2078
- * modified
2079
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
2080
- * RSV1 bit
2081
- * @param {Function} [cb] Callback
2082
- * @private
2083
- */
2084
- getBlobData(blob, compress, options, cb) {
2085
- this._bufferedBytes += options[kByteLength];
2086
- this._state = GET_BLOB_DATA;
2087
-
2088
- blob
2089
- .arrayBuffer()
2090
- .then((arrayBuffer) => {
2091
- if (this._socket.destroyed) {
2092
- const err = new Error(
2093
- 'The socket was closed while the blob was being read'
2094
- );
2095
-
2096
- //
2097
- // `callCallbacks` is called in the next tick to ensure that errors
2098
- // that might be thrown in the callbacks behave like errors thrown
2099
- // outside the promise chain.
2100
- //
2101
- process.nextTick(callCallbacks, this, err, cb);
2102
- return;
2103
- }
2104
-
2105
- this._bufferedBytes -= options[kByteLength];
2106
- const data = toBuffer(arrayBuffer);
2107
-
2108
- if (!compress) {
2109
- this._state = DEFAULT;
2110
- this.sendFrame(Sender.frame(data, options), cb);
2111
- this.dequeue();
2112
- } else {
2113
- this.dispatch(data, compress, options, cb);
2114
- }
2115
- })
2116
- .catch((err) => {
2117
- //
2118
- // `onError` is called in the next tick for the same reason that
2119
- // `callCallbacks` above is.
2120
- //
2121
- process.nextTick(onError, this, err, cb);
2122
- });
2123
- }
2124
-
2125
- /**
2126
- * Dispatches a message.
2127
- *
2128
- * @param {(Buffer|String)} data The message to send
2129
- * @param {Boolean} [compress=false] Specifies whether or not to compress
2130
- * `data`
2131
- * @param {Object} options Options object
2132
- * @param {Boolean} [options.fin=false] Specifies whether or not to set the
2133
- * FIN bit
2134
- * @param {Function} [options.generateMask] The function used to generate the
2135
- * masking key
2136
- * @param {Boolean} [options.mask=false] Specifies whether or not to mask
2137
- * `data`
2138
- * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
2139
- * key
2140
- * @param {Number} options.opcode The opcode
2141
- * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
2142
- * modified
2143
- * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
2144
- * RSV1 bit
2145
- * @param {Function} [cb] Callback
2146
- * @private
2147
- */
2148
- dispatch(data, compress, options, cb) {
2149
- if (!compress) {
2150
- this.sendFrame(Sender.frame(data, options), cb);
2151
- return;
2152
- }
2153
-
2154
- const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
2155
-
2156
- this._bufferedBytes += options[kByteLength];
2157
- this._state = DEFLATING;
2158
- perMessageDeflate.compress(data, options.fin, (_, buf) => {
2159
- if (this._socket.destroyed) {
2160
- const err = new Error(
2161
- 'The socket was closed while data was being compressed'
2162
- );
2163
-
2164
- callCallbacks(this, err, cb);
2165
- return;
2166
- }
2167
-
2168
- this._bufferedBytes -= options[kByteLength];
2169
- this._state = DEFAULT;
2170
- options.readOnly = false;
2171
- this.sendFrame(Sender.frame(buf, options), cb);
2172
- this.dequeue();
2173
- });
2174
- }
2175
-
2176
- /**
2177
- * Executes queued send operations.
2178
- *
2179
- * @private
2180
- */
2181
- dequeue() {
2182
- while (this._state === DEFAULT && this._queue.length) {
2183
- const params = this._queue.shift();
2184
-
2185
- this._bufferedBytes -= params[3][kByteLength];
2186
- Reflect.apply(params[0], this, params.slice(1));
2187
- }
2188
- }
2189
-
2190
- /**
2191
- * Enqueues a send operation.
2192
- *
2193
- * @param {Array} params Send operation parameters.
2194
- * @private
2195
- */
2196
- enqueue(params) {
2197
- this._bufferedBytes += params[3][kByteLength];
2198
- this._queue.push(params);
2199
- }
2200
-
2201
- /**
2202
- * Sends a frame.
2203
- *
2204
- * @param {Buffer[]} list The frame to send
2205
- * @param {Function} [cb] Callback
2206
- * @private
2207
- */
2208
- sendFrame(list, cb) {
2209
- if (list.length === 2) {
2210
- this._socket.cork();
2211
- this._socket.write(list[0]);
2212
- this._socket.write(list[1], cb);
2213
- this._socket.uncork();
2214
- } else {
2215
- this._socket.write(list[0], cb);
2216
- }
2217
- }
2218
- }
2219
-
2220
- sender = Sender;
2221
-
2222
- /**
2223
- * Calls queued callbacks with an error.
2224
- *
2225
- * @param {Sender} sender The `Sender` instance
2226
- * @param {Error} err The error to call the callbacks with
2227
- * @param {Function} [cb] The first callback
2228
- * @private
2229
- */
2230
- function callCallbacks(sender, err, cb) {
2231
- if (typeof cb === 'function') cb(err);
2232
-
2233
- for (let i = 0; i < sender._queue.length; i++) {
2234
- const params = sender._queue[i];
2235
- const callback = params[params.length - 1];
2236
-
2237
- if (typeof callback === 'function') callback(err);
2238
- }
2239
- }
2240
-
2241
- /**
2242
- * Handles a `Sender` error.
2243
- *
2244
- * @param {Sender} sender The `Sender` instance
2245
- * @param {Error} err The error
2246
- * @param {Function} [cb] The first pending callback
2247
- * @private
2248
- */
2249
- function onError(sender, err, cb) {
2250
- callCallbacks(sender, err, cb);
2251
- sender.onerror(err);
2252
- }
2253
- return sender;
2254
- }
2255
-
2256
- requireSender();
2257
-
2258
- var eventTarget;
2259
- var hasRequiredEventTarget;
2260
-
2261
- function requireEventTarget () {
2262
- if (hasRequiredEventTarget) return eventTarget;
2263
- hasRequiredEventTarget = 1;
2264
-
2265
- const { kForOnEventAttribute, kListener } = requireConstants();
2266
-
2267
- const kCode = Symbol('kCode');
2268
- const kData = Symbol('kData');
2269
- const kError = Symbol('kError');
2270
- const kMessage = Symbol('kMessage');
2271
- const kReason = Symbol('kReason');
2272
- const kTarget = Symbol('kTarget');
2273
- const kType = Symbol('kType');
2274
- const kWasClean = Symbol('kWasClean');
2275
-
2276
- /**
2277
- * Class representing an event.
2278
- */
2279
- class Event {
2280
- /**
2281
- * Create a new `Event`.
2282
- *
2283
- * @param {String} type The name of the event
2284
- * @throws {TypeError} If the `type` argument is not specified
2285
- */
2286
- constructor(type) {
2287
- this[kTarget] = null;
2288
- this[kType] = type;
2289
- }
2290
-
2291
- /**
2292
- * @type {*}
2293
- */
2294
- get target() {
2295
- return this[kTarget];
2296
- }
2297
-
2298
- /**
2299
- * @type {String}
2300
- */
2301
- get type() {
2302
- return this[kType];
2303
- }
2304
- }
2305
-
2306
- Object.defineProperty(Event.prototype, 'target', { enumerable: true });
2307
- Object.defineProperty(Event.prototype, 'type', { enumerable: true });
2308
-
2309
- /**
2310
- * Class representing a close event.
2311
- *
2312
- * @extends Event
2313
- */
2314
- class CloseEvent extends Event {
2315
- /**
2316
- * Create a new `CloseEvent`.
2317
- *
2318
- * @param {String} type The name of the event
2319
- * @param {Object} [options] A dictionary object that allows for setting
2320
- * attributes via object members of the same name
2321
- * @param {Number} [options.code=0] The status code explaining why the
2322
- * connection was closed
2323
- * @param {String} [options.reason=''] A human-readable string explaining why
2324
- * the connection was closed
2325
- * @param {Boolean} [options.wasClean=false] Indicates whether or not the
2326
- * connection was cleanly closed
2327
- */
2328
- constructor(type, options = {}) {
2329
- super(type);
2330
-
2331
- this[kCode] = options.code === undefined ? 0 : options.code;
2332
- this[kReason] = options.reason === undefined ? '' : options.reason;
2333
- this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;
2334
- }
2335
-
2336
- /**
2337
- * @type {Number}
2338
- */
2339
- get code() {
2340
- return this[kCode];
2341
- }
2342
-
2343
- /**
2344
- * @type {String}
2345
- */
2346
- get reason() {
2347
- return this[kReason];
2348
- }
2349
-
2350
- /**
2351
- * @type {Boolean}
2352
- */
2353
- get wasClean() {
2354
- return this[kWasClean];
2355
- }
2356
- }
2357
-
2358
- Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });
2359
- Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });
2360
- Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });
2361
-
2362
- /**
2363
- * Class representing an error event.
2364
- *
2365
- * @extends Event
2366
- */
2367
- class ErrorEvent extends Event {
2368
- /**
2369
- * Create a new `ErrorEvent`.
2370
- *
2371
- * @param {String} type The name of the event
2372
- * @param {Object} [options] A dictionary object that allows for setting
2373
- * attributes via object members of the same name
2374
- * @param {*} [options.error=null] The error that generated this event
2375
- * @param {String} [options.message=''] The error message
2376
- */
2377
- constructor(type, options = {}) {
2378
- super(type);
2379
-
2380
- this[kError] = options.error === undefined ? null : options.error;
2381
- this[kMessage] = options.message === undefined ? '' : options.message;
2382
- }
2383
-
2384
- /**
2385
- * @type {*}
2386
- */
2387
- get error() {
2388
- return this[kError];
2389
- }
2390
-
2391
- /**
2392
- * @type {String}
2393
- */
2394
- get message() {
2395
- return this[kMessage];
2396
- }
2397
- }
2398
-
2399
- Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });
2400
- Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });
2401
-
2402
- /**
2403
- * Class representing a message event.
2404
- *
2405
- * @extends Event
2406
- */
2407
- class MessageEvent extends Event {
2408
- /**
2409
- * Create a new `MessageEvent`.
2410
- *
2411
- * @param {String} type The name of the event
2412
- * @param {Object} [options] A dictionary object that allows for setting
2413
- * attributes via object members of the same name
2414
- * @param {*} [options.data=null] The message content
2415
- */
2416
- constructor(type, options = {}) {
2417
- super(type);
2418
-
2419
- this[kData] = options.data === undefined ? null : options.data;
2420
- }
2421
-
2422
- /**
2423
- * @type {*}
2424
- */
2425
- get data() {
2426
- return this[kData];
2427
- }
2428
- }
2429
-
2430
- Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });
2431
-
2432
- /**
2433
- * This provides methods for emulating the `EventTarget` interface. It's not
2434
- * meant to be used directly.
2435
- *
2436
- * @mixin
2437
- */
2438
- const EventTarget = {
2439
- /**
2440
- * Register an event listener.
2441
- *
2442
- * @param {String} type A string representing the event type to listen for
2443
- * @param {(Function|Object)} handler The listener to add
2444
- * @param {Object} [options] An options object specifies characteristics about
2445
- * the event listener
2446
- * @param {Boolean} [options.once=false] A `Boolean` indicating that the
2447
- * listener should be invoked at most once after being added. If `true`,
2448
- * the listener would be automatically removed when invoked.
2449
- * @public
2450
- */
2451
- addEventListener(type, handler, options = {}) {
2452
- for (const listener of this.listeners(type)) {
2453
- if (
2454
- !options[kForOnEventAttribute] &&
2455
- listener[kListener] === handler &&
2456
- !listener[kForOnEventAttribute]
2457
- ) {
2458
- return;
2459
- }
2460
- }
2461
-
2462
- let wrapper;
2463
-
2464
- if (type === 'message') {
2465
- wrapper = function onMessage(data, isBinary) {
2466
- const event = new MessageEvent('message', {
2467
- data: isBinary ? data : data.toString()
2468
- });
2469
-
2470
- event[kTarget] = this;
2471
- callListener(handler, this, event);
2472
- };
2473
- } else if (type === 'close') {
2474
- wrapper = function onClose(code, message) {
2475
- const event = new CloseEvent('close', {
2476
- code,
2477
- reason: message.toString(),
2478
- wasClean: this._closeFrameReceived && this._closeFrameSent
2479
- });
2480
-
2481
- event[kTarget] = this;
2482
- callListener(handler, this, event);
2483
- };
2484
- } else if (type === 'error') {
2485
- wrapper = function onError(error) {
2486
- const event = new ErrorEvent('error', {
2487
- error,
2488
- message: error.message
2489
- });
2490
-
2491
- event[kTarget] = this;
2492
- callListener(handler, this, event);
2493
- };
2494
- } else if (type === 'open') {
2495
- wrapper = function onOpen() {
2496
- const event = new Event('open');
2497
-
2498
- event[kTarget] = this;
2499
- callListener(handler, this, event);
2500
- };
2501
- } else {
2502
- return;
2503
- }
2504
-
2505
- wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
2506
- wrapper[kListener] = handler;
2507
-
2508
- if (options.once) {
2509
- this.once(type, wrapper);
2510
- } else {
2511
- this.on(type, wrapper);
2512
- }
2513
- },
2514
-
2515
- /**
2516
- * Remove an event listener.
2517
- *
2518
- * @param {String} type A string representing the event type to remove
2519
- * @param {(Function|Object)} handler The listener to remove
2520
- * @public
2521
- */
2522
- removeEventListener(type, handler) {
2523
- for (const listener of this.listeners(type)) {
2524
- if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
2525
- this.removeListener(type, listener);
2526
- break;
2527
- }
2528
- }
2529
- }
2530
- };
2531
-
2532
- eventTarget = {
2533
- CloseEvent,
2534
- ErrorEvent,
2535
- Event,
2536
- EventTarget,
2537
- MessageEvent
2538
- };
2539
-
2540
- /**
2541
- * Call an event listener
2542
- *
2543
- * @param {(Function|Object)} listener The listener to call
2544
- * @param {*} thisArg The value to use as `this`` when calling the listener
2545
- * @param {Event} event The event to pass to the listener
2546
- * @private
2547
- */
2548
- function callListener(listener, thisArg, event) {
2549
- if (typeof listener === 'object' && listener.handleEvent) {
2550
- listener.handleEvent.call(listener, event);
2551
- } else {
2552
- listener.call(thisArg, event);
2553
- }
2554
- }
2555
- return eventTarget;
2556
- }
2557
-
2558
- var extension;
2559
- var hasRequiredExtension;
2560
-
2561
- function requireExtension () {
2562
- if (hasRequiredExtension) return extension;
2563
- hasRequiredExtension = 1;
2564
-
2565
- const { tokenChars } = requireValidation();
2566
-
2567
- /**
2568
- * Adds an offer to the map of extension offers or a parameter to the map of
2569
- * parameters.
2570
- *
2571
- * @param {Object} dest The map of extension offers or parameters
2572
- * @param {String} name The extension or parameter name
2573
- * @param {(Object|Boolean|String)} elem The extension parameters or the
2574
- * parameter value
2575
- * @private
2576
- */
2577
- function push(dest, name, elem) {
2578
- if (dest[name] === undefined) dest[name] = [elem];
2579
- else dest[name].push(elem);
2580
- }
2581
-
2582
- /**
2583
- * Parses the `Sec-WebSocket-Extensions` header into an object.
2584
- *
2585
- * @param {String} header The field value of the header
2586
- * @return {Object} The parsed object
2587
- * @public
2588
- */
2589
- function parse(header) {
2590
- const offers = Object.create(null);
2591
- let params = Object.create(null);
2592
- let mustUnescape = false;
2593
- let isEscaping = false;
2594
- let inQuotes = false;
2595
- let extensionName;
2596
- let paramName;
2597
- let start = -1;
2598
- let code = -1;
2599
- let end = -1;
2600
- let i = 0;
2601
-
2602
- for (; i < header.length; i++) {
2603
- code = header.charCodeAt(i);
2604
-
2605
- if (extensionName === undefined) {
2606
- if (end === -1 && tokenChars[code] === 1) {
2607
- if (start === -1) start = i;
2608
- } else if (
2609
- i !== 0 &&
2610
- (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
2611
- ) {
2612
- if (end === -1 && start !== -1) end = i;
2613
- } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
2614
- if (start === -1) {
2615
- throw new SyntaxError(`Unexpected character at index ${i}`);
2616
- }
2617
-
2618
- if (end === -1) end = i;
2619
- const name = header.slice(start, end);
2620
- if (code === 0x2c) {
2621
- push(offers, name, params);
2622
- params = Object.create(null);
2623
- } else {
2624
- extensionName = name;
2625
- }
2626
-
2627
- start = end = -1;
2628
- } else {
2629
- throw new SyntaxError(`Unexpected character at index ${i}`);
2630
- }
2631
- } else if (paramName === undefined) {
2632
- if (end === -1 && tokenChars[code] === 1) {
2633
- if (start === -1) start = i;
2634
- } else if (code === 0x20 || code === 0x09) {
2635
- if (end === -1 && start !== -1) end = i;
2636
- } else if (code === 0x3b || code === 0x2c) {
2637
- if (start === -1) {
2638
- throw new SyntaxError(`Unexpected character at index ${i}`);
2639
- }
2640
-
2641
- if (end === -1) end = i;
2642
- push(params, header.slice(start, end), true);
2643
- if (code === 0x2c) {
2644
- push(offers, extensionName, params);
2645
- params = Object.create(null);
2646
- extensionName = undefined;
2647
- }
2648
-
2649
- start = end = -1;
2650
- } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
2651
- paramName = header.slice(start, i);
2652
- start = end = -1;
2653
- } else {
2654
- throw new SyntaxError(`Unexpected character at index ${i}`);
2655
- }
2656
- } else {
2657
- //
2658
- // The value of a quoted-string after unescaping must conform to the
2659
- // token ABNF, so only token characters are valid.
2660
- // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
2661
- //
2662
- if (isEscaping) {
2663
- if (tokenChars[code] !== 1) {
2664
- throw new SyntaxError(`Unexpected character at index ${i}`);
2665
- }
2666
- if (start === -1) start = i;
2667
- else if (!mustUnescape) mustUnescape = true;
2668
- isEscaping = false;
2669
- } else if (inQuotes) {
2670
- if (tokenChars[code] === 1) {
2671
- if (start === -1) start = i;
2672
- } else if (code === 0x22 /* '"' */ && start !== -1) {
2673
- inQuotes = false;
2674
- end = i;
2675
- } else if (code === 0x5c /* '\' */) {
2676
- isEscaping = true;
2677
- } else {
2678
- throw new SyntaxError(`Unexpected character at index ${i}`);
2679
- }
2680
- } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
2681
- inQuotes = true;
2682
- } else if (end === -1 && tokenChars[code] === 1) {
2683
- if (start === -1) start = i;
2684
- } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
2685
- if (end === -1) end = i;
2686
- } else if (code === 0x3b || code === 0x2c) {
2687
- if (start === -1) {
2688
- throw new SyntaxError(`Unexpected character at index ${i}`);
2689
- }
2690
-
2691
- if (end === -1) end = i;
2692
- let value = header.slice(start, end);
2693
- if (mustUnescape) {
2694
- value = value.replace(/\\/g, '');
2695
- mustUnescape = false;
2696
- }
2697
- push(params, paramName, value);
2698
- if (code === 0x2c) {
2699
- push(offers, extensionName, params);
2700
- params = Object.create(null);
2701
- extensionName = undefined;
2702
- }
2703
-
2704
- paramName = undefined;
2705
- start = end = -1;
2706
- } else {
2707
- throw new SyntaxError(`Unexpected character at index ${i}`);
2708
- }
2709
- }
2710
- }
2711
-
2712
- if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
2713
- throw new SyntaxError('Unexpected end of input');
2714
- }
2715
-
2716
- if (end === -1) end = i;
2717
- const token = header.slice(start, end);
2718
- if (extensionName === undefined) {
2719
- push(offers, token, params);
2720
- } else {
2721
- if (paramName === undefined) {
2722
- push(params, token, true);
2723
- } else if (mustUnescape) {
2724
- push(params, paramName, token.replace(/\\/g, ''));
2725
- } else {
2726
- push(params, paramName, token);
2727
- }
2728
- push(offers, extensionName, params);
2729
- }
2730
-
2731
- return offers;
2732
- }
2733
-
2734
- /**
2735
- * Builds the `Sec-WebSocket-Extensions` header field value.
2736
- *
2737
- * @param {Object} extensions The map of extensions and parameters to format
2738
- * @return {String} A string representing the given object
2739
- * @public
2740
- */
2741
- function format(extensions) {
2742
- return Object.keys(extensions)
2743
- .map((extension) => {
2744
- let configurations = extensions[extension];
2745
- if (!Array.isArray(configurations)) configurations = [configurations];
2746
- return configurations
2747
- .map((params) => {
2748
- return [extension]
2749
- .concat(
2750
- Object.keys(params).map((k) => {
2751
- let values = params[k];
2752
- if (!Array.isArray(values)) values = [values];
2753
- return values
2754
- .map((v) => (v === true ? k : `${k}=${v}`))
2755
- .join('; ');
2756
- })
2757
- )
2758
- .join('; ');
2759
- })
2760
- .join(', ');
2761
- })
2762
- .join(', ');
2763
- }
2764
-
2765
- extension = { format, parse };
2766
- return extension;
2767
- }
2768
-
2769
- /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$", "caughtErrors": "none" }] */
2770
-
2771
- var websocket;
2772
- var hasRequiredWebsocket;
2773
-
2774
- function requireWebsocket () {
2775
- if (hasRequiredWebsocket) return websocket;
2776
- hasRequiredWebsocket = 1;
2777
-
2778
- const EventEmitter = require$$0$3;
2779
- const https = require$$1$1;
2780
- const http = require$$2;
2781
- const net = require$$3;
2782
- const tls = require$$4;
2783
- const { randomBytes, createHash } = require$$1;
2784
- const { URL } = require$$7;
2785
-
2786
- const PerMessageDeflate = requirePermessageDeflate();
2787
- const Receiver = requireReceiver();
2788
- const Sender = requireSender();
2789
- const { isBlob } = requireValidation();
2790
-
2791
- const {
2792
- BINARY_TYPES,
2793
- EMPTY_BUFFER,
2794
- GUID,
2795
- kForOnEventAttribute,
2796
- kListener,
2797
- kStatusCode,
2798
- kWebSocket,
2799
- NOOP
2800
- } = requireConstants();
2801
- const {
2802
- EventTarget: { addEventListener, removeEventListener }
2803
- } = requireEventTarget();
2804
- const { format, parse } = requireExtension();
2805
- const { toBuffer } = requireBufferUtil();
2806
-
2807
- const closeTimeout = 30 * 1000;
2808
- const kAborted = Symbol('kAborted');
2809
- const protocolVersions = [8, 13];
2810
- const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
2811
- const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
2812
-
2813
- /**
2814
- * Class representing a WebSocket.
2815
- *
2816
- * @extends EventEmitter
2817
- */
2818
- class WebSocket extends EventEmitter {
2819
- /**
2820
- * Create a new `WebSocket`.
2821
- *
2822
- * @param {(String|URL)} address The URL to which to connect
2823
- * @param {(String|String[])} [protocols] The subprotocols
2824
- * @param {Object} [options] Connection options
2825
- */
2826
- constructor(address, protocols, options) {
2827
- super();
2828
-
2829
- this._binaryType = BINARY_TYPES[0];
2830
- this._closeCode = 1006;
2831
- this._closeFrameReceived = false;
2832
- this._closeFrameSent = false;
2833
- this._closeMessage = EMPTY_BUFFER;
2834
- this._closeTimer = null;
2835
- this._errorEmitted = false;
2836
- this._extensions = {};
2837
- this._paused = false;
2838
- this._protocol = '';
2839
- this._readyState = WebSocket.CONNECTING;
2840
- this._receiver = null;
2841
- this._sender = null;
2842
- this._socket = null;
2843
-
2844
- if (address !== null) {
2845
- this._bufferedAmount = 0;
2846
- this._isServer = false;
2847
- this._redirects = 0;
2848
-
2849
- if (protocols === undefined) {
2850
- protocols = [];
2851
- } else if (!Array.isArray(protocols)) {
2852
- if (typeof protocols === 'object' && protocols !== null) {
2853
- options = protocols;
2854
- protocols = [];
2855
- } else {
2856
- protocols = [protocols];
2857
- }
2858
- }
2859
-
2860
- initAsClient(this, address, protocols, options);
2861
- } else {
2862
- this._autoPong = options.autoPong;
2863
- this._isServer = true;
2864
- }
2865
- }
2866
-
2867
- /**
2868
- * For historical reasons, the custom "nodebuffer" type is used by the default
2869
- * instead of "blob".
2870
- *
2871
- * @type {String}
2872
- */
2873
- get binaryType() {
2874
- return this._binaryType;
2875
- }
2876
-
2877
- set binaryType(type) {
2878
- if (!BINARY_TYPES.includes(type)) return;
2879
-
2880
- this._binaryType = type;
2881
-
2882
- //
2883
- // Allow to change `binaryType` on the fly.
2884
- //
2885
- if (this._receiver) this._receiver._binaryType = type;
2886
- }
2887
-
2888
- /**
2889
- * @type {Number}
2890
- */
2891
- get bufferedAmount() {
2892
- if (!this._socket) return this._bufferedAmount;
2893
-
2894
- return this._socket._writableState.length + this._sender._bufferedBytes;
2895
- }
2896
-
2897
- /**
2898
- * @type {String}
2899
- */
2900
- get extensions() {
2901
- return Object.keys(this._extensions).join();
2902
- }
2903
-
2904
- /**
2905
- * @type {Boolean}
2906
- */
2907
- get isPaused() {
2908
- return this._paused;
2909
- }
2910
-
2911
- /**
2912
- * @type {Function}
2913
- */
2914
- /* istanbul ignore next */
2915
- get onclose() {
2916
- return null;
2917
- }
2918
-
2919
- /**
2920
- * @type {Function}
2921
- */
2922
- /* istanbul ignore next */
2923
- get onerror() {
2924
- return null;
2925
- }
2926
-
2927
- /**
2928
- * @type {Function}
2929
- */
2930
- /* istanbul ignore next */
2931
- get onopen() {
2932
- return null;
2933
- }
2934
-
2935
- /**
2936
- * @type {Function}
2937
- */
2938
- /* istanbul ignore next */
2939
- get onmessage() {
2940
- return null;
2941
- }
2942
-
2943
- /**
2944
- * @type {String}
2945
- */
2946
- get protocol() {
2947
- return this._protocol;
2948
- }
2949
-
2950
- /**
2951
- * @type {Number}
2952
- */
2953
- get readyState() {
2954
- return this._readyState;
2955
- }
2956
-
2957
- /**
2958
- * @type {String}
2959
- */
2960
- get url() {
2961
- return this._url;
2962
- }
2963
-
2964
- /**
2965
- * Set up the socket and the internal resources.
2966
- *
2967
- * @param {Duplex} socket The network socket between the server and client
2968
- * @param {Buffer} head The first packet of the upgraded stream
2969
- * @param {Object} options Options object
2970
- * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
2971
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
2972
- * multiple times in the same tick
2973
- * @param {Function} [options.generateMask] The function used to generate the
2974
- * masking key
2975
- * @param {Number} [options.maxPayload=0] The maximum allowed message size
2976
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
2977
- * not to skip UTF-8 validation for text and close messages
2978
- * @private
2979
- */
2980
- setSocket(socket, head, options) {
2981
- const receiver = new Receiver({
2982
- allowSynchronousEvents: options.allowSynchronousEvents,
2983
- binaryType: this.binaryType,
2984
- extensions: this._extensions,
2985
- isServer: this._isServer,
2986
- maxPayload: options.maxPayload,
2987
- skipUTF8Validation: options.skipUTF8Validation
2988
- });
2989
-
2990
- const sender = new Sender(socket, this._extensions, options.generateMask);
2991
-
2992
- this._receiver = receiver;
2993
- this._sender = sender;
2994
- this._socket = socket;
2995
-
2996
- receiver[kWebSocket] = this;
2997
- sender[kWebSocket] = this;
2998
- socket[kWebSocket] = this;
2999
-
3000
- receiver.on('conclude', receiverOnConclude);
3001
- receiver.on('drain', receiverOnDrain);
3002
- receiver.on('error', receiverOnError);
3003
- receiver.on('message', receiverOnMessage);
3004
- receiver.on('ping', receiverOnPing);
3005
- receiver.on('pong', receiverOnPong);
3006
-
3007
- sender.onerror = senderOnError;
3008
-
3009
- //
3010
- // These methods may not be available if `socket` is just a `Duplex`.
3011
- //
3012
- if (socket.setTimeout) socket.setTimeout(0);
3013
- if (socket.setNoDelay) socket.setNoDelay();
3014
-
3015
- if (head.length > 0) socket.unshift(head);
3016
-
3017
- socket.on('close', socketOnClose);
3018
- socket.on('data', socketOnData);
3019
- socket.on('end', socketOnEnd);
3020
- socket.on('error', socketOnError);
3021
-
3022
- this._readyState = WebSocket.OPEN;
3023
- this.emit('open');
3024
- }
3025
-
3026
- /**
3027
- * Emit the `'close'` event.
3028
- *
3029
- * @private
3030
- */
3031
- emitClose() {
3032
- if (!this._socket) {
3033
- this._readyState = WebSocket.CLOSED;
3034
- this.emit('close', this._closeCode, this._closeMessage);
3035
- return;
3036
- }
3037
-
3038
- if (this._extensions[PerMessageDeflate.extensionName]) {
3039
- this._extensions[PerMessageDeflate.extensionName].cleanup();
3040
- }
3041
-
3042
- this._receiver.removeAllListeners();
3043
- this._readyState = WebSocket.CLOSED;
3044
- this.emit('close', this._closeCode, this._closeMessage);
3045
- }
3046
-
3047
- /**
3048
- * Start a closing handshake.
3049
- *
3050
- * +----------+ +-----------+ +----------+
3051
- * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
3052
- * | +----------+ +-----------+ +----------+ |
3053
- * +----------+ +-----------+ |
3054
- * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
3055
- * +----------+ +-----------+ |
3056
- * | | | +---+ |
3057
- * +------------------------+-->|fin| - - - -
3058
- * | +---+ | +---+
3059
- * - - - - -|fin|<---------------------+
3060
- * +---+
3061
- *
3062
- * @param {Number} [code] Status code explaining why the connection is closing
3063
- * @param {(String|Buffer)} [data] The reason why the connection is
3064
- * closing
3065
- * @public
3066
- */
3067
- close(code, data) {
3068
- if (this.readyState === WebSocket.CLOSED) return;
3069
- if (this.readyState === WebSocket.CONNECTING) {
3070
- const msg = 'WebSocket was closed before the connection was established';
3071
- abortHandshake(this, this._req, msg);
3072
- return;
3073
- }
3074
-
3075
- if (this.readyState === WebSocket.CLOSING) {
3076
- if (
3077
- this._closeFrameSent &&
3078
- (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
3079
- ) {
3080
- this._socket.end();
3081
- }
3082
-
3083
- return;
3084
- }
3085
-
3086
- this._readyState = WebSocket.CLOSING;
3087
- this._sender.close(code, data, !this._isServer, (err) => {
3088
- //
3089
- // This error is handled by the `'error'` listener on the socket. We only
3090
- // want to know if the close frame has been sent here.
3091
- //
3092
- if (err) return;
3093
-
3094
- this._closeFrameSent = true;
3095
-
3096
- if (
3097
- this._closeFrameReceived ||
3098
- this._receiver._writableState.errorEmitted
3099
- ) {
3100
- this._socket.end();
3101
- }
3102
- });
3103
-
3104
- setCloseTimer(this);
3105
- }
3106
-
3107
- /**
3108
- * Pause the socket.
3109
- *
3110
- * @public
3111
- */
3112
- pause() {
3113
- if (
3114
- this.readyState === WebSocket.CONNECTING ||
3115
- this.readyState === WebSocket.CLOSED
3116
- ) {
3117
- return;
3118
- }
3119
-
3120
- this._paused = true;
3121
- this._socket.pause();
3122
- }
3123
-
3124
- /**
3125
- * Send a ping.
3126
- *
3127
- * @param {*} [data] The data to send
3128
- * @param {Boolean} [mask] Indicates whether or not to mask `data`
3129
- * @param {Function} [cb] Callback which is executed when the ping is sent
3130
- * @public
3131
- */
3132
- ping(data, mask, cb) {
3133
- if (this.readyState === WebSocket.CONNECTING) {
3134
- throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
3135
- }
3136
-
3137
- if (typeof data === 'function') {
3138
- cb = data;
3139
- data = mask = undefined;
3140
- } else if (typeof mask === 'function') {
3141
- cb = mask;
3142
- mask = undefined;
3143
- }
3144
-
3145
- if (typeof data === 'number') data = data.toString();
3146
-
3147
- if (this.readyState !== WebSocket.OPEN) {
3148
- sendAfterClose(this, data, cb);
3149
- return;
3150
- }
3151
-
3152
- if (mask === undefined) mask = !this._isServer;
3153
- this._sender.ping(data || EMPTY_BUFFER, mask, cb);
3154
- }
3155
-
3156
- /**
3157
- * Send a pong.
3158
- *
3159
- * @param {*} [data] The data to send
3160
- * @param {Boolean} [mask] Indicates whether or not to mask `data`
3161
- * @param {Function} [cb] Callback which is executed when the pong is sent
3162
- * @public
3163
- */
3164
- pong(data, mask, cb) {
3165
- if (this.readyState === WebSocket.CONNECTING) {
3166
- throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
3167
- }
3168
-
3169
- if (typeof data === 'function') {
3170
- cb = data;
3171
- data = mask = undefined;
3172
- } else if (typeof mask === 'function') {
3173
- cb = mask;
3174
- mask = undefined;
3175
- }
3176
-
3177
- if (typeof data === 'number') data = data.toString();
3178
-
3179
- if (this.readyState !== WebSocket.OPEN) {
3180
- sendAfterClose(this, data, cb);
3181
- return;
3182
- }
3183
-
3184
- if (mask === undefined) mask = !this._isServer;
3185
- this._sender.pong(data || EMPTY_BUFFER, mask, cb);
3186
- }
3187
-
3188
- /**
3189
- * Resume the socket.
3190
- *
3191
- * @public
3192
- */
3193
- resume() {
3194
- if (
3195
- this.readyState === WebSocket.CONNECTING ||
3196
- this.readyState === WebSocket.CLOSED
3197
- ) {
3198
- return;
3199
- }
3200
-
3201
- this._paused = false;
3202
- if (!this._receiver._writableState.needDrain) this._socket.resume();
3203
- }
3204
-
3205
- /**
3206
- * Send a data message.
3207
- *
3208
- * @param {*} data The message to send
3209
- * @param {Object} [options] Options object
3210
- * @param {Boolean} [options.binary] Specifies whether `data` is binary or
3211
- * text
3212
- * @param {Boolean} [options.compress] Specifies whether or not to compress
3213
- * `data`
3214
- * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
3215
- * last one
3216
- * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
3217
- * @param {Function} [cb] Callback which is executed when data is written out
3218
- * @public
3219
- */
3220
- send(data, options, cb) {
3221
- if (this.readyState === WebSocket.CONNECTING) {
3222
- throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
3223
- }
3224
-
3225
- if (typeof options === 'function') {
3226
- cb = options;
3227
- options = {};
3228
- }
3229
-
3230
- if (typeof data === 'number') data = data.toString();
3231
-
3232
- if (this.readyState !== WebSocket.OPEN) {
3233
- sendAfterClose(this, data, cb);
3234
- return;
3235
- }
3236
-
3237
- const opts = {
3238
- binary: typeof data !== 'string',
3239
- mask: !this._isServer,
3240
- compress: true,
3241
- fin: true,
3242
- ...options
3243
- };
3244
-
3245
- if (!this._extensions[PerMessageDeflate.extensionName]) {
3246
- opts.compress = false;
3247
- }
3248
-
3249
- this._sender.send(data || EMPTY_BUFFER, opts, cb);
3250
- }
3251
-
3252
- /**
3253
- * Forcibly close the connection.
3254
- *
3255
- * @public
3256
- */
3257
- terminate() {
3258
- if (this.readyState === WebSocket.CLOSED) return;
3259
- if (this.readyState === WebSocket.CONNECTING) {
3260
- const msg = 'WebSocket was closed before the connection was established';
3261
- abortHandshake(this, this._req, msg);
3262
- return;
3263
- }
3264
-
3265
- if (this._socket) {
3266
- this._readyState = WebSocket.CLOSING;
3267
- this._socket.destroy();
3268
- }
3269
- }
3270
- }
3271
-
3272
- /**
3273
- * @constant {Number} CONNECTING
3274
- * @memberof WebSocket
3275
- */
3276
- Object.defineProperty(WebSocket, 'CONNECTING', {
3277
- enumerable: true,
3278
- value: readyStates.indexOf('CONNECTING')
3279
- });
3280
-
3281
- /**
3282
- * @constant {Number} CONNECTING
3283
- * @memberof WebSocket.prototype
3284
- */
3285
- Object.defineProperty(WebSocket.prototype, 'CONNECTING', {
3286
- enumerable: true,
3287
- value: readyStates.indexOf('CONNECTING')
3288
- });
3289
-
3290
- /**
3291
- * @constant {Number} OPEN
3292
- * @memberof WebSocket
3293
- */
3294
- Object.defineProperty(WebSocket, 'OPEN', {
3295
- enumerable: true,
3296
- value: readyStates.indexOf('OPEN')
3297
- });
3298
-
3299
- /**
3300
- * @constant {Number} OPEN
3301
- * @memberof WebSocket.prototype
3302
- */
3303
- Object.defineProperty(WebSocket.prototype, 'OPEN', {
3304
- enumerable: true,
3305
- value: readyStates.indexOf('OPEN')
3306
- });
3307
-
3308
- /**
3309
- * @constant {Number} CLOSING
3310
- * @memberof WebSocket
3311
- */
3312
- Object.defineProperty(WebSocket, 'CLOSING', {
3313
- enumerable: true,
3314
- value: readyStates.indexOf('CLOSING')
3315
- });
3316
-
3317
- /**
3318
- * @constant {Number} CLOSING
3319
- * @memberof WebSocket.prototype
3320
- */
3321
- Object.defineProperty(WebSocket.prototype, 'CLOSING', {
3322
- enumerable: true,
3323
- value: readyStates.indexOf('CLOSING')
3324
- });
3325
-
3326
- /**
3327
- * @constant {Number} CLOSED
3328
- * @memberof WebSocket
3329
- */
3330
- Object.defineProperty(WebSocket, 'CLOSED', {
3331
- enumerable: true,
3332
- value: readyStates.indexOf('CLOSED')
3333
- });
3334
-
3335
- /**
3336
- * @constant {Number} CLOSED
3337
- * @memberof WebSocket.prototype
3338
- */
3339
- Object.defineProperty(WebSocket.prototype, 'CLOSED', {
3340
- enumerable: true,
3341
- value: readyStates.indexOf('CLOSED')
3342
- });
3343
-
3344
- [
3345
- 'binaryType',
3346
- 'bufferedAmount',
3347
- 'extensions',
3348
- 'isPaused',
3349
- 'protocol',
3350
- 'readyState',
3351
- 'url'
3352
- ].forEach((property) => {
3353
- Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
3354
- });
3355
-
3356
- //
3357
- // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
3358
- // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
3359
- //
3360
- ['open', 'error', 'close', 'message'].forEach((method) => {
3361
- Object.defineProperty(WebSocket.prototype, `on${method}`, {
3362
- enumerable: true,
3363
- get() {
3364
- for (const listener of this.listeners(method)) {
3365
- if (listener[kForOnEventAttribute]) return listener[kListener];
3366
- }
3367
-
3368
- return null;
3369
- },
3370
- set(handler) {
3371
- for (const listener of this.listeners(method)) {
3372
- if (listener[kForOnEventAttribute]) {
3373
- this.removeListener(method, listener);
3374
- break;
3375
- }
3376
- }
3377
-
3378
- if (typeof handler !== 'function') return;
3379
-
3380
- this.addEventListener(method, handler, {
3381
- [kForOnEventAttribute]: true
3382
- });
3383
- }
3384
- });
3385
- });
3386
-
3387
- WebSocket.prototype.addEventListener = addEventListener;
3388
- WebSocket.prototype.removeEventListener = removeEventListener;
3389
-
3390
- websocket = WebSocket;
3391
-
3392
- /**
3393
- * Initialize a WebSocket client.
3394
- *
3395
- * @param {WebSocket} websocket The client to initialize
3396
- * @param {(String|URL)} address The URL to which to connect
3397
- * @param {Array} protocols The subprotocols
3398
- * @param {Object} [options] Connection options
3399
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any
3400
- * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
3401
- * times in the same tick
3402
- * @param {Boolean} [options.autoPong=true] Specifies whether or not to
3403
- * automatically send a pong in response to a ping
3404
- * @param {Function} [options.finishRequest] A function which can be used to
3405
- * customize the headers of each http request before it is sent
3406
- * @param {Boolean} [options.followRedirects=false] Whether or not to follow
3407
- * redirects
3408
- * @param {Function} [options.generateMask] The function used to generate the
3409
- * masking key
3410
- * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
3411
- * handshake request
3412
- * @param {Number} [options.maxPayload=104857600] The maximum allowed message
3413
- * size
3414
- * @param {Number} [options.maxRedirects=10] The maximum number of redirects
3415
- * allowed
3416
- * @param {String} [options.origin] Value of the `Origin` or
3417
- * `Sec-WebSocket-Origin` header
3418
- * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
3419
- * permessage-deflate
3420
- * @param {Number} [options.protocolVersion=13] Value of the
3421
- * `Sec-WebSocket-Version` header
3422
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
3423
- * not to skip UTF-8 validation for text and close messages
3424
- * @private
3425
- */
3426
- function initAsClient(websocket, address, protocols, options) {
3427
- const opts = {
3428
- allowSynchronousEvents: true,
3429
- autoPong: true,
3430
- protocolVersion: protocolVersions[1],
3431
- maxPayload: 100 * 1024 * 1024,
3432
- skipUTF8Validation: false,
3433
- perMessageDeflate: true,
3434
- followRedirects: false,
3435
- maxRedirects: 10,
3436
- ...options,
3437
- socketPath: undefined,
3438
- hostname: undefined,
3439
- protocol: undefined,
3440
- timeout: undefined,
3441
- method: 'GET',
3442
- host: undefined,
3443
- path: undefined,
3444
- port: undefined
3445
- };
3446
-
3447
- websocket._autoPong = opts.autoPong;
3448
-
3449
- if (!protocolVersions.includes(opts.protocolVersion)) {
3450
- throw new RangeError(
3451
- `Unsupported protocol version: ${opts.protocolVersion} ` +
3452
- `(supported versions: ${protocolVersions.join(', ')})`
3453
- );
3454
- }
3455
-
3456
- let parsedUrl;
3457
-
3458
- if (address instanceof URL) {
3459
- parsedUrl = address;
3460
- } else {
3461
- try {
3462
- parsedUrl = new URL(address);
3463
- } catch (e) {
3464
- throw new SyntaxError(`Invalid URL: ${address}`);
3465
- }
3466
- }
3467
-
3468
- if (parsedUrl.protocol === 'http:') {
3469
- parsedUrl.protocol = 'ws:';
3470
- } else if (parsedUrl.protocol === 'https:') {
3471
- parsedUrl.protocol = 'wss:';
3472
- }
3473
-
3474
- websocket._url = parsedUrl.href;
3475
-
3476
- const isSecure = parsedUrl.protocol === 'wss:';
3477
- const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
3478
- let invalidUrlMessage;
3479
-
3480
- if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
3481
- invalidUrlMessage =
3482
- 'The URL\'s protocol must be one of "ws:", "wss:", ' +
3483
- '"http:", "https", or "ws+unix:"';
3484
- } else if (isIpcUrl && !parsedUrl.pathname) {
3485
- invalidUrlMessage = "The URL's pathname is empty";
3486
- } else if (parsedUrl.hash) {
3487
- invalidUrlMessage = 'The URL contains a fragment identifier';
3488
- }
3489
-
3490
- if (invalidUrlMessage) {
3491
- const err = new SyntaxError(invalidUrlMessage);
3492
-
3493
- if (websocket._redirects === 0) {
3494
- throw err;
3495
- } else {
3496
- emitErrorAndClose(websocket, err);
3497
- return;
3498
- }
3499
- }
3500
-
3501
- const defaultPort = isSecure ? 443 : 80;
3502
- const key = randomBytes(16).toString('base64');
3503
- const request = isSecure ? https.request : http.request;
3504
- const protocolSet = new Set();
3505
- let perMessageDeflate;
3506
-
3507
- opts.createConnection =
3508
- opts.createConnection || (isSecure ? tlsConnect : netConnect);
3509
- opts.defaultPort = opts.defaultPort || defaultPort;
3510
- opts.port = parsedUrl.port || defaultPort;
3511
- opts.host = parsedUrl.hostname.startsWith('[')
3512
- ? parsedUrl.hostname.slice(1, -1)
3513
- : parsedUrl.hostname;
3514
- opts.headers = {
3515
- ...opts.headers,
3516
- 'Sec-WebSocket-Version': opts.protocolVersion,
3517
- 'Sec-WebSocket-Key': key,
3518
- Connection: 'Upgrade',
3519
- Upgrade: 'websocket'
3520
- };
3521
- opts.path = parsedUrl.pathname + parsedUrl.search;
3522
- opts.timeout = opts.handshakeTimeout;
3523
-
3524
- if (opts.perMessageDeflate) {
3525
- perMessageDeflate = new PerMessageDeflate(
3526
- opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
3527
- false,
3528
- opts.maxPayload
3529
- );
3530
- opts.headers['Sec-WebSocket-Extensions'] = format({
3531
- [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
3532
- });
3533
- }
3534
- if (protocols.length) {
3535
- for (const protocol of protocols) {
3536
- if (
3537
- typeof protocol !== 'string' ||
3538
- !subprotocolRegex.test(protocol) ||
3539
- protocolSet.has(protocol)
3540
- ) {
3541
- throw new SyntaxError(
3542
- 'An invalid or duplicated subprotocol was specified'
3543
- );
3544
- }
3545
-
3546
- protocolSet.add(protocol);
3547
- }
3548
-
3549
- opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');
3550
- }
3551
- if (opts.origin) {
3552
- if (opts.protocolVersion < 13) {
3553
- opts.headers['Sec-WebSocket-Origin'] = opts.origin;
3554
- } else {
3555
- opts.headers.Origin = opts.origin;
3556
- }
3557
- }
3558
- if (parsedUrl.username || parsedUrl.password) {
3559
- opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
3560
- }
3561
-
3562
- if (isIpcUrl) {
3563
- const parts = opts.path.split(':');
3564
-
3565
- opts.socketPath = parts[0];
3566
- opts.path = parts[1];
3567
- }
3568
-
3569
- let req;
3570
-
3571
- if (opts.followRedirects) {
3572
- if (websocket._redirects === 0) {
3573
- websocket._originalIpc = isIpcUrl;
3574
- websocket._originalSecure = isSecure;
3575
- websocket._originalHostOrSocketPath = isIpcUrl
3576
- ? opts.socketPath
3577
- : parsedUrl.host;
3578
-
3579
- const headers = options && options.headers;
3580
-
3581
- //
3582
- // Shallow copy the user provided options so that headers can be changed
3583
- // without mutating the original object.
3584
- //
3585
- options = { ...options, headers: {} };
3586
-
3587
- if (headers) {
3588
- for (const [key, value] of Object.entries(headers)) {
3589
- options.headers[key.toLowerCase()] = value;
3590
- }
3591
- }
3592
- } else if (websocket.listenerCount('redirect') === 0) {
3593
- const isSameHost = isIpcUrl
3594
- ? websocket._originalIpc
3595
- ? opts.socketPath === websocket._originalHostOrSocketPath
3596
- : false
3597
- : websocket._originalIpc
3598
- ? false
3599
- : parsedUrl.host === websocket._originalHostOrSocketPath;
3600
-
3601
- if (!isSameHost || (websocket._originalSecure && !isSecure)) {
3602
- //
3603
- // Match curl 7.77.0 behavior and drop the following headers. These
3604
- // headers are also dropped when following a redirect to a subdomain.
3605
- //
3606
- delete opts.headers.authorization;
3607
- delete opts.headers.cookie;
3608
-
3609
- if (!isSameHost) delete opts.headers.host;
3610
-
3611
- opts.auth = undefined;
3612
- }
3613
- }
3614
-
3615
- //
3616
- // Match curl 7.77.0 behavior and make the first `Authorization` header win.
3617
- // If the `Authorization` header is set, then there is nothing to do as it
3618
- // will take precedence.
3619
- //
3620
- if (opts.auth && !options.headers.authorization) {
3621
- options.headers.authorization =
3622
- 'Basic ' + Buffer.from(opts.auth).toString('base64');
3623
- }
3624
-
3625
- req = websocket._req = request(opts);
3626
-
3627
- if (websocket._redirects) {
3628
- //
3629
- // Unlike what is done for the `'upgrade'` event, no early exit is
3630
- // triggered here if the user calls `websocket.close()` or
3631
- // `websocket.terminate()` from a listener of the `'redirect'` event. This
3632
- // is because the user can also call `request.destroy()` with an error
3633
- // before calling `websocket.close()` or `websocket.terminate()` and this
3634
- // would result in an error being emitted on the `request` object with no
3635
- // `'error'` event listeners attached.
3636
- //
3637
- websocket.emit('redirect', websocket.url, req);
3638
- }
3639
- } else {
3640
- req = websocket._req = request(opts);
3641
- }
3642
-
3643
- if (opts.timeout) {
3644
- req.on('timeout', () => {
3645
- abortHandshake(websocket, req, 'Opening handshake has timed out');
3646
- });
3647
- }
3648
-
3649
- req.on('error', (err) => {
3650
- if (req === null || req[kAborted]) return;
3651
-
3652
- req = websocket._req = null;
3653
- emitErrorAndClose(websocket, err);
3654
- });
3655
-
3656
- req.on('response', (res) => {
3657
- const location = res.headers.location;
3658
- const statusCode = res.statusCode;
3659
-
3660
- if (
3661
- location &&
3662
- opts.followRedirects &&
3663
- statusCode >= 300 &&
3664
- statusCode < 400
3665
- ) {
3666
- if (++websocket._redirects > opts.maxRedirects) {
3667
- abortHandshake(websocket, req, 'Maximum redirects exceeded');
3668
- return;
3669
- }
3670
-
3671
- req.abort();
3672
-
3673
- let addr;
3674
-
3675
- try {
3676
- addr = new URL(location, address);
3677
- } catch (e) {
3678
- const err = new SyntaxError(`Invalid URL: ${location}`);
3679
- emitErrorAndClose(websocket, err);
3680
- return;
3681
- }
3682
-
3683
- initAsClient(websocket, addr, protocols, options);
3684
- } else if (!websocket.emit('unexpected-response', req, res)) {
3685
- abortHandshake(
3686
- websocket,
3687
- req,
3688
- `Unexpected server response: ${res.statusCode}`
3689
- );
3690
- }
3691
- });
3692
-
3693
- req.on('upgrade', (res, socket, head) => {
3694
- websocket.emit('upgrade', res);
3695
-
3696
- //
3697
- // The user may have closed the connection from a listener of the
3698
- // `'upgrade'` event.
3699
- //
3700
- if (websocket.readyState !== WebSocket.CONNECTING) return;
3701
-
3702
- req = websocket._req = null;
3703
-
3704
- const upgrade = res.headers.upgrade;
3705
-
3706
- if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
3707
- abortHandshake(websocket, socket, 'Invalid Upgrade header');
3708
- return;
3709
- }
3710
-
3711
- const digest = createHash('sha1')
3712
- .update(key + GUID)
3713
- .digest('base64');
3714
-
3715
- if (res.headers['sec-websocket-accept'] !== digest) {
3716
- abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
3717
- return;
3718
- }
3719
-
3720
- const serverProt = res.headers['sec-websocket-protocol'];
3721
- let protError;
3722
-
3723
- if (serverProt !== undefined) {
3724
- if (!protocolSet.size) {
3725
- protError = 'Server sent a subprotocol but none was requested';
3726
- } else if (!protocolSet.has(serverProt)) {
3727
- protError = 'Server sent an invalid subprotocol';
3728
- }
3729
- } else if (protocolSet.size) {
3730
- protError = 'Server sent no subprotocol';
3731
- }
3732
-
3733
- if (protError) {
3734
- abortHandshake(websocket, socket, protError);
3735
- return;
3736
- }
3737
-
3738
- if (serverProt) websocket._protocol = serverProt;
3739
-
3740
- const secWebSocketExtensions = res.headers['sec-websocket-extensions'];
3741
-
3742
- if (secWebSocketExtensions !== undefined) {
3743
- if (!perMessageDeflate) {
3744
- const message =
3745
- 'Server sent a Sec-WebSocket-Extensions header but no extension ' +
3746
- 'was requested';
3747
- abortHandshake(websocket, socket, message);
3748
- return;
3749
- }
3750
-
3751
- let extensions;
3752
-
3753
- try {
3754
- extensions = parse(secWebSocketExtensions);
3755
- } catch (err) {
3756
- const message = 'Invalid Sec-WebSocket-Extensions header';
3757
- abortHandshake(websocket, socket, message);
3758
- return;
3759
- }
3760
-
3761
- const extensionNames = Object.keys(extensions);
3762
-
3763
- if (
3764
- extensionNames.length !== 1 ||
3765
- extensionNames[0] !== PerMessageDeflate.extensionName
3766
- ) {
3767
- const message = 'Server indicated an extension that was not requested';
3768
- abortHandshake(websocket, socket, message);
3769
- return;
3770
- }
3771
-
3772
- try {
3773
- perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
3774
- } catch (err) {
3775
- const message = 'Invalid Sec-WebSocket-Extensions header';
3776
- abortHandshake(websocket, socket, message);
3777
- return;
3778
- }
3779
-
3780
- websocket._extensions[PerMessageDeflate.extensionName] =
3781
- perMessageDeflate;
3782
- }
3783
-
3784
- websocket.setSocket(socket, head, {
3785
- allowSynchronousEvents: opts.allowSynchronousEvents,
3786
- generateMask: opts.generateMask,
3787
- maxPayload: opts.maxPayload,
3788
- skipUTF8Validation: opts.skipUTF8Validation
3789
- });
3790
- });
3791
-
3792
- if (opts.finishRequest) {
3793
- opts.finishRequest(req, websocket);
3794
- } else {
3795
- req.end();
3796
- }
3797
- }
3798
-
3799
- /**
3800
- * Emit the `'error'` and `'close'` events.
3801
- *
3802
- * @param {WebSocket} websocket The WebSocket instance
3803
- * @param {Error} The error to emit
3804
- * @private
3805
- */
3806
- function emitErrorAndClose(websocket, err) {
3807
- websocket._readyState = WebSocket.CLOSING;
3808
- //
3809
- // The following assignment is practically useless and is done only for
3810
- // consistency.
3811
- //
3812
- websocket._errorEmitted = true;
3813
- websocket.emit('error', err);
3814
- websocket.emitClose();
3815
- }
3816
-
3817
- /**
3818
- * Create a `net.Socket` and initiate a connection.
3819
- *
3820
- * @param {Object} options Connection options
3821
- * @return {net.Socket} The newly created socket used to start the connection
3822
- * @private
3823
- */
3824
- function netConnect(options) {
3825
- options.path = options.socketPath;
3826
- return net.connect(options);
3827
- }
3828
-
3829
- /**
3830
- * Create a `tls.TLSSocket` and initiate a connection.
3831
- *
3832
- * @param {Object} options Connection options
3833
- * @return {tls.TLSSocket} The newly created socket used to start the connection
3834
- * @private
3835
- */
3836
- function tlsConnect(options) {
3837
- options.path = undefined;
3838
-
3839
- if (!options.servername && options.servername !== '') {
3840
- options.servername = net.isIP(options.host) ? '' : options.host;
3841
- }
3842
-
3843
- return tls.connect(options);
3844
- }
3845
-
3846
- /**
3847
- * Abort the handshake and emit an error.
3848
- *
3849
- * @param {WebSocket} websocket The WebSocket instance
3850
- * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
3851
- * abort or the socket to destroy
3852
- * @param {String} message The error message
3853
- * @private
3854
- */
3855
- function abortHandshake(websocket, stream, message) {
3856
- websocket._readyState = WebSocket.CLOSING;
3857
-
3858
- const err = new Error(message);
3859
- Error.captureStackTrace(err, abortHandshake);
3860
-
3861
- if (stream.setHeader) {
3862
- stream[kAborted] = true;
3863
- stream.abort();
3864
-
3865
- if (stream.socket && !stream.socket.destroyed) {
3866
- //
3867
- // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if
3868
- // called after the request completed. See
3869
- // https://github.com/websockets/ws/issues/1869.
3870
- //
3871
- stream.socket.destroy();
3872
- }
3873
-
3874
- process.nextTick(emitErrorAndClose, websocket, err);
3875
- } else {
3876
- stream.destroy(err);
3877
- stream.once('error', websocket.emit.bind(websocket, 'error'));
3878
- stream.once('close', websocket.emitClose.bind(websocket));
3879
- }
3880
- }
3881
-
3882
- /**
3883
- * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
3884
- * when the `readyState` attribute is `CLOSING` or `CLOSED`.
3885
- *
3886
- * @param {WebSocket} websocket The WebSocket instance
3887
- * @param {*} [data] The data to send
3888
- * @param {Function} [cb] Callback
3889
- * @private
3890
- */
3891
- function sendAfterClose(websocket, data, cb) {
3892
- if (data) {
3893
- const length = isBlob(data) ? data.size : toBuffer(data).length;
3894
-
3895
- //
3896
- // The `_bufferedAmount` property is used only when the peer is a client and
3897
- // the opening handshake fails. Under these circumstances, in fact, the
3898
- // `setSocket()` method is not called, so the `_socket` and `_sender`
3899
- // properties are set to `null`.
3900
- //
3901
- if (websocket._socket) websocket._sender._bufferedBytes += length;
3902
- else websocket._bufferedAmount += length;
3903
- }
3904
-
3905
- if (cb) {
3906
- const err = new Error(
3907
- `WebSocket is not open: readyState ${websocket.readyState} ` +
3908
- `(${readyStates[websocket.readyState]})`
3909
- );
3910
- process.nextTick(cb, err);
3911
- }
3912
- }
3913
-
3914
- /**
3915
- * The listener of the `Receiver` `'conclude'` event.
3916
- *
3917
- * @param {Number} code The status code
3918
- * @param {Buffer} reason The reason for closing
3919
- * @private
3920
- */
3921
- function receiverOnConclude(code, reason) {
3922
- const websocket = this[kWebSocket];
3923
-
3924
- websocket._closeFrameReceived = true;
3925
- websocket._closeMessage = reason;
3926
- websocket._closeCode = code;
3927
-
3928
- if (websocket._socket[kWebSocket] === undefined) return;
3929
-
3930
- websocket._socket.removeListener('data', socketOnData);
3931
- process.nextTick(resume, websocket._socket);
3932
-
3933
- if (code === 1005) websocket.close();
3934
- else websocket.close(code, reason);
3935
- }
3936
-
3937
- /**
3938
- * The listener of the `Receiver` `'drain'` event.
3939
- *
3940
- * @private
3941
- */
3942
- function receiverOnDrain() {
3943
- const websocket = this[kWebSocket];
3944
-
3945
- if (!websocket.isPaused) websocket._socket.resume();
3946
- }
3947
-
3948
- /**
3949
- * The listener of the `Receiver` `'error'` event.
3950
- *
3951
- * @param {(RangeError|Error)} err The emitted error
3952
- * @private
3953
- */
3954
- function receiverOnError(err) {
3955
- const websocket = this[kWebSocket];
3956
-
3957
- if (websocket._socket[kWebSocket] !== undefined) {
3958
- websocket._socket.removeListener('data', socketOnData);
3959
-
3960
- //
3961
- // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
3962
- // https://github.com/websockets/ws/issues/1940.
3963
- //
3964
- process.nextTick(resume, websocket._socket);
3965
-
3966
- websocket.close(err[kStatusCode]);
3967
- }
3968
-
3969
- if (!websocket._errorEmitted) {
3970
- websocket._errorEmitted = true;
3971
- websocket.emit('error', err);
3972
- }
3973
- }
3974
-
3975
- /**
3976
- * The listener of the `Receiver` `'finish'` event.
3977
- *
3978
- * @private
3979
- */
3980
- function receiverOnFinish() {
3981
- this[kWebSocket].emitClose();
3982
- }
3983
-
3984
- /**
3985
- * The listener of the `Receiver` `'message'` event.
3986
- *
3987
- * @param {Buffer|ArrayBuffer|Buffer[])} data The message
3988
- * @param {Boolean} isBinary Specifies whether the message is binary or not
3989
- * @private
3990
- */
3991
- function receiverOnMessage(data, isBinary) {
3992
- this[kWebSocket].emit('message', data, isBinary);
3993
- }
3994
-
3995
- /**
3996
- * The listener of the `Receiver` `'ping'` event.
3997
- *
3998
- * @param {Buffer} data The data included in the ping frame
3999
- * @private
4000
- */
4001
- function receiverOnPing(data) {
4002
- const websocket = this[kWebSocket];
4003
-
4004
- if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
4005
- websocket.emit('ping', data);
4006
- }
4007
-
4008
- /**
4009
- * The listener of the `Receiver` `'pong'` event.
4010
- *
4011
- * @param {Buffer} data The data included in the pong frame
4012
- * @private
4013
- */
4014
- function receiverOnPong(data) {
4015
- this[kWebSocket].emit('pong', data);
4016
- }
4017
-
4018
- /**
4019
- * Resume a readable stream
4020
- *
4021
- * @param {Readable} stream The readable stream
4022
- * @private
4023
- */
4024
- function resume(stream) {
4025
- stream.resume();
4026
- }
4027
-
4028
- /**
4029
- * The `Sender` error event handler.
4030
- *
4031
- * @param {Error} The error
4032
- * @private
4033
- */
4034
- function senderOnError(err) {
4035
- const websocket = this[kWebSocket];
4036
-
4037
- if (websocket.readyState === WebSocket.CLOSED) return;
4038
- if (websocket.readyState === WebSocket.OPEN) {
4039
- websocket._readyState = WebSocket.CLOSING;
4040
- setCloseTimer(websocket);
4041
- }
4042
-
4043
- //
4044
- // `socket.end()` is used instead of `socket.destroy()` to allow the other
4045
- // peer to finish sending queued data. There is no need to set a timer here
4046
- // because `CLOSING` means that it is already set or not needed.
4047
- //
4048
- this._socket.end();
4049
-
4050
- if (!websocket._errorEmitted) {
4051
- websocket._errorEmitted = true;
4052
- websocket.emit('error', err);
4053
- }
4054
- }
4055
-
4056
- /**
4057
- * Set a timer to destroy the underlying raw socket of a WebSocket.
4058
- *
4059
- * @param {WebSocket} websocket The WebSocket instance
4060
- * @private
4061
- */
4062
- function setCloseTimer(websocket) {
4063
- websocket._closeTimer = setTimeout(
4064
- websocket._socket.destroy.bind(websocket._socket),
4065
- closeTimeout
4066
- );
4067
- }
4068
-
4069
- /**
4070
- * The listener of the socket `'close'` event.
4071
- *
4072
- * @private
4073
- */
4074
- function socketOnClose() {
4075
- const websocket = this[kWebSocket];
4076
-
4077
- this.removeListener('close', socketOnClose);
4078
- this.removeListener('data', socketOnData);
4079
- this.removeListener('end', socketOnEnd);
4080
-
4081
- websocket._readyState = WebSocket.CLOSING;
4082
-
4083
- let chunk;
4084
-
4085
- //
4086
- // The close frame might not have been received or the `'end'` event emitted,
4087
- // for example, if the socket was destroyed due to an error. Ensure that the
4088
- // `receiver` stream is closed after writing any remaining buffered data to
4089
- // it. If the readable side of the socket is in flowing mode then there is no
4090
- // buffered data as everything has been already written and `readable.read()`
4091
- // will return `null`. If instead, the socket is paused, any possible buffered
4092
- // data will be read as a single chunk.
4093
- //
4094
- if (
4095
- !this._readableState.endEmitted &&
4096
- !websocket._closeFrameReceived &&
4097
- !websocket._receiver._writableState.errorEmitted &&
4098
- (chunk = websocket._socket.read()) !== null
4099
- ) {
4100
- websocket._receiver.write(chunk);
4101
- }
4102
-
4103
- websocket._receiver.end();
4104
-
4105
- this[kWebSocket] = undefined;
4106
-
4107
- clearTimeout(websocket._closeTimer);
4108
-
4109
- if (
4110
- websocket._receiver._writableState.finished ||
4111
- websocket._receiver._writableState.errorEmitted
4112
- ) {
4113
- websocket.emitClose();
4114
- } else {
4115
- websocket._receiver.on('error', receiverOnFinish);
4116
- websocket._receiver.on('finish', receiverOnFinish);
4117
- }
4118
- }
4119
-
4120
- /**
4121
- * The listener of the socket `'data'` event.
4122
- *
4123
- * @param {Buffer} chunk A chunk of data
4124
- * @private
4125
- */
4126
- function socketOnData(chunk) {
4127
- if (!this[kWebSocket]._receiver.write(chunk)) {
4128
- this.pause();
4129
- }
4130
- }
4131
-
4132
- /**
4133
- * The listener of the socket `'end'` event.
4134
- *
4135
- * @private
4136
- */
4137
- function socketOnEnd() {
4138
- const websocket = this[kWebSocket];
4139
-
4140
- websocket._readyState = WebSocket.CLOSING;
4141
- websocket._receiver.end();
4142
- this.end();
4143
- }
4144
-
4145
- /**
4146
- * The listener of the socket `'error'` event.
4147
- *
4148
- * @private
4149
- */
4150
- function socketOnError() {
4151
- const websocket = this[kWebSocket];
4152
-
4153
- this.removeListener('error', socketOnError);
4154
- this.on('error', NOOP);
4155
-
4156
- if (websocket) {
4157
- websocket._readyState = WebSocket.CLOSING;
4158
- this.destroy();
4159
- }
4160
- }
4161
- return websocket;
4162
- }
4163
-
4164
- var websocketExports = requireWebsocket();
4165
- var WebSocket = /*@__PURE__*/getDefaultExportFromCjs(websocketExports);
4166
-
4167
- var subprotocol;
4168
- var hasRequiredSubprotocol;
4169
-
4170
- function requireSubprotocol () {
4171
- if (hasRequiredSubprotocol) return subprotocol;
4172
- hasRequiredSubprotocol = 1;
4173
-
4174
- const { tokenChars } = requireValidation();
4175
-
4176
- /**
4177
- * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
4178
- *
4179
- * @param {String} header The field value of the header
4180
- * @return {Set} The subprotocol names
4181
- * @public
4182
- */
4183
- function parse(header) {
4184
- const protocols = new Set();
4185
- let start = -1;
4186
- let end = -1;
4187
- let i = 0;
4188
-
4189
- for (i; i < header.length; i++) {
4190
- const code = header.charCodeAt(i);
4191
-
4192
- if (end === -1 && tokenChars[code] === 1) {
4193
- if (start === -1) start = i;
4194
- } else if (
4195
- i !== 0 &&
4196
- (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
4197
- ) {
4198
- if (end === -1 && start !== -1) end = i;
4199
- } else if (code === 0x2c /* ',' */) {
4200
- if (start === -1) {
4201
- throw new SyntaxError(`Unexpected character at index ${i}`);
4202
- }
4203
-
4204
- if (end === -1) end = i;
4205
-
4206
- const protocol = header.slice(start, end);
4207
-
4208
- if (protocols.has(protocol)) {
4209
- throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
4210
- }
4211
-
4212
- protocols.add(protocol);
4213
- start = end = -1;
4214
- } else {
4215
- throw new SyntaxError(`Unexpected character at index ${i}`);
4216
- }
4217
- }
4218
-
4219
- if (start === -1 || end !== -1) {
4220
- throw new SyntaxError('Unexpected end of input');
4221
- }
4222
-
4223
- const protocol = header.slice(start, i);
4224
-
4225
- if (protocols.has(protocol)) {
4226
- throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
4227
- }
4228
-
4229
- protocols.add(protocol);
4230
- return protocols;
4231
- }
4232
-
4233
- subprotocol = { parse };
4234
- return subprotocol;
4235
- }
4236
-
4237
- /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
4238
-
4239
- var websocketServer;
4240
- var hasRequiredWebsocketServer;
4241
-
4242
- function requireWebsocketServer () {
4243
- if (hasRequiredWebsocketServer) return websocketServer;
4244
- hasRequiredWebsocketServer = 1;
4245
-
4246
- const EventEmitter = require$$0$3;
4247
- const http = require$$2;
4248
- const { createHash } = require$$1;
4249
-
4250
- const extension = requireExtension();
4251
- const PerMessageDeflate = requirePermessageDeflate();
4252
- const subprotocol = requireSubprotocol();
4253
- const WebSocket = requireWebsocket();
4254
- const { GUID, kWebSocket } = requireConstants();
4255
-
4256
- const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
4257
-
4258
- const RUNNING = 0;
4259
- const CLOSING = 1;
4260
- const CLOSED = 2;
4261
-
4262
- /**
4263
- * Class representing a WebSocket server.
4264
- *
4265
- * @extends EventEmitter
4266
- */
4267
- class WebSocketServer extends EventEmitter {
4268
- /**
4269
- * Create a `WebSocketServer` instance.
4270
- *
4271
- * @param {Object} options Configuration options
4272
- * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
4273
- * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
4274
- * multiple times in the same tick
4275
- * @param {Boolean} [options.autoPong=true] Specifies whether or not to
4276
- * automatically send a pong in response to a ping
4277
- * @param {Number} [options.backlog=511] The maximum length of the queue of
4278
- * pending connections
4279
- * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
4280
- * track clients
4281
- * @param {Function} [options.handleProtocols] A hook to handle protocols
4282
- * @param {String} [options.host] The hostname where to bind the server
4283
- * @param {Number} [options.maxPayload=104857600] The maximum allowed message
4284
- * size
4285
- * @param {Boolean} [options.noServer=false] Enable no server mode
4286
- * @param {String} [options.path] Accept only connections matching this path
4287
- * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
4288
- * permessage-deflate
4289
- * @param {Number} [options.port] The port where to bind the server
4290
- * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
4291
- * server to use
4292
- * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
4293
- * not to skip UTF-8 validation for text and close messages
4294
- * @param {Function} [options.verifyClient] A hook to reject connections
4295
- * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
4296
- * class to use. It must be the `WebSocket` class or class that extends it
4297
- * @param {Function} [callback] A listener for the `listening` event
4298
- */
4299
- constructor(options, callback) {
4300
- super();
4301
-
4302
- options = {
4303
- allowSynchronousEvents: true,
4304
- autoPong: true,
4305
- maxPayload: 100 * 1024 * 1024,
4306
- skipUTF8Validation: false,
4307
- perMessageDeflate: false,
4308
- handleProtocols: null,
4309
- clientTracking: true,
4310
- verifyClient: null,
4311
- noServer: false,
4312
- backlog: null, // use default (511 as implemented in net.js)
4313
- server: null,
4314
- host: null,
4315
- path: null,
4316
- port: null,
4317
- WebSocket,
4318
- ...options
4319
- };
4320
-
4321
- if (
4322
- (options.port == null && !options.server && !options.noServer) ||
4323
- (options.port != null && (options.server || options.noServer)) ||
4324
- (options.server && options.noServer)
4325
- ) {
4326
- throw new TypeError(
4327
- 'One and only one of the "port", "server", or "noServer" options ' +
4328
- 'must be specified'
4329
- );
4330
- }
4331
-
4332
- if (options.port != null) {
4333
- this._server = http.createServer((req, res) => {
4334
- const body = http.STATUS_CODES[426];
4335
-
4336
- res.writeHead(426, {
4337
- 'Content-Length': body.length,
4338
- 'Content-Type': 'text/plain'
4339
- });
4340
- res.end(body);
4341
- });
4342
- this._server.listen(
4343
- options.port,
4344
- options.host,
4345
- options.backlog,
4346
- callback
4347
- );
4348
- } else if (options.server) {
4349
- this._server = options.server;
4350
- }
4351
-
4352
- if (this._server) {
4353
- const emitConnection = this.emit.bind(this, 'connection');
4354
-
4355
- this._removeListeners = addListeners(this._server, {
4356
- listening: this.emit.bind(this, 'listening'),
4357
- error: this.emit.bind(this, 'error'),
4358
- upgrade: (req, socket, head) => {
4359
- this.handleUpgrade(req, socket, head, emitConnection);
4360
- }
4361
- });
4362
- }
4363
-
4364
- if (options.perMessageDeflate === true) options.perMessageDeflate = {};
4365
- if (options.clientTracking) {
4366
- this.clients = new Set();
4367
- this._shouldEmitClose = false;
4368
- }
4369
-
4370
- this.options = options;
4371
- this._state = RUNNING;
4372
- }
4373
-
4374
- /**
4375
- * Returns the bound address, the address family name, and port of the server
4376
- * as reported by the operating system if listening on an IP socket.
4377
- * If the server is listening on a pipe or UNIX domain socket, the name is
4378
- * returned as a string.
4379
- *
4380
- * @return {(Object|String|null)} The address of the server
4381
- * @public
4382
- */
4383
- address() {
4384
- if (this.options.noServer) {
4385
- throw new Error('The server is operating in "noServer" mode');
4386
- }
4387
-
4388
- if (!this._server) return null;
4389
- return this._server.address();
4390
- }
4391
-
4392
- /**
4393
- * Stop the server from accepting new connections and emit the `'close'` event
4394
- * when all existing connections are closed.
4395
- *
4396
- * @param {Function} [cb] A one-time listener for the `'close'` event
4397
- * @public
4398
- */
4399
- close(cb) {
4400
- if (this._state === CLOSED) {
4401
- if (cb) {
4402
- this.once('close', () => {
4403
- cb(new Error('The server is not running'));
4404
- });
4405
- }
4406
-
4407
- process.nextTick(emitClose, this);
4408
- return;
4409
- }
4410
-
4411
- if (cb) this.once('close', cb);
4412
-
4413
- if (this._state === CLOSING) return;
4414
- this._state = CLOSING;
4415
-
4416
- if (this.options.noServer || this.options.server) {
4417
- if (this._server) {
4418
- this._removeListeners();
4419
- this._removeListeners = this._server = null;
4420
- }
4421
-
4422
- if (this.clients) {
4423
- if (!this.clients.size) {
4424
- process.nextTick(emitClose, this);
4425
- } else {
4426
- this._shouldEmitClose = true;
4427
- }
4428
- } else {
4429
- process.nextTick(emitClose, this);
4430
- }
4431
- } else {
4432
- const server = this._server;
4433
-
4434
- this._removeListeners();
4435
- this._removeListeners = this._server = null;
4436
-
4437
- //
4438
- // The HTTP/S server was created internally. Close it, and rely on its
4439
- // `'close'` event.
4440
- //
4441
- server.close(() => {
4442
- emitClose(this);
4443
- });
4444
- }
4445
- }
4446
-
4447
- /**
4448
- * See if a given request should be handled by this server instance.
4449
- *
4450
- * @param {http.IncomingMessage} req Request object to inspect
4451
- * @return {Boolean} `true` if the request is valid, else `false`
4452
- * @public
4453
- */
4454
- shouldHandle(req) {
4455
- if (this.options.path) {
4456
- const index = req.url.indexOf('?');
4457
- const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
4458
-
4459
- if (pathname !== this.options.path) return false;
4460
- }
4461
-
4462
- return true;
4463
- }
4464
-
4465
- /**
4466
- * Handle a HTTP Upgrade request.
4467
- *
4468
- * @param {http.IncomingMessage} req The request object
4469
- * @param {Duplex} socket The network socket between the server and client
4470
- * @param {Buffer} head The first packet of the upgraded stream
4471
- * @param {Function} cb Callback
4472
- * @public
4473
- */
4474
- handleUpgrade(req, socket, head, cb) {
4475
- socket.on('error', socketOnError);
4476
-
4477
- const key = req.headers['sec-websocket-key'];
4478
- const upgrade = req.headers.upgrade;
4479
- const version = +req.headers['sec-websocket-version'];
4480
-
4481
- if (req.method !== 'GET') {
4482
- const message = 'Invalid HTTP method';
4483
- abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
4484
- return;
4485
- }
4486
-
4487
- if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
4488
- const message = 'Invalid Upgrade header';
4489
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
4490
- return;
4491
- }
4492
-
4493
- if (key === undefined || !keyRegex.test(key)) {
4494
- const message = 'Missing or invalid Sec-WebSocket-Key header';
4495
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
4496
- return;
4497
- }
4498
-
4499
- if (version !== 8 && version !== 13) {
4500
- const message = 'Missing or invalid Sec-WebSocket-Version header';
4501
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
4502
- return;
4503
- }
4504
-
4505
- if (!this.shouldHandle(req)) {
4506
- abortHandshake(socket, 400);
4507
- return;
4508
- }
4509
-
4510
- const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
4511
- let protocols = new Set();
4512
-
4513
- if (secWebSocketProtocol !== undefined) {
4514
- try {
4515
- protocols = subprotocol.parse(secWebSocketProtocol);
4516
- } catch (err) {
4517
- const message = 'Invalid Sec-WebSocket-Protocol header';
4518
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
4519
- return;
4520
- }
4521
- }
4522
-
4523
- const secWebSocketExtensions = req.headers['sec-websocket-extensions'];
4524
- const extensions = {};
4525
-
4526
- if (
4527
- this.options.perMessageDeflate &&
4528
- secWebSocketExtensions !== undefined
4529
- ) {
4530
- const perMessageDeflate = new PerMessageDeflate(
4531
- this.options.perMessageDeflate,
4532
- true,
4533
- this.options.maxPayload
4534
- );
4535
-
4536
- try {
4537
- const offers = extension.parse(secWebSocketExtensions);
4538
-
4539
- if (offers[PerMessageDeflate.extensionName]) {
4540
- perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
4541
- extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
4542
- }
4543
- } catch (err) {
4544
- const message =
4545
- 'Invalid or unacceptable Sec-WebSocket-Extensions header';
4546
- abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
4547
- return;
4548
- }
4549
- }
4550
-
4551
- //
4552
- // Optionally call external client verification handler.
4553
- //
4554
- if (this.options.verifyClient) {
4555
- const info = {
4556
- origin:
4557
- req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
4558
- secure: !!(req.socket.authorized || req.socket.encrypted),
4559
- req
4560
- };
4561
-
4562
- if (this.options.verifyClient.length === 2) {
4563
- this.options.verifyClient(info, (verified, code, message, headers) => {
4564
- if (!verified) {
4565
- return abortHandshake(socket, code || 401, message, headers);
4566
- }
4567
-
4568
- this.completeUpgrade(
4569
- extensions,
4570
- key,
4571
- protocols,
4572
- req,
4573
- socket,
4574
- head,
4575
- cb
4576
- );
4577
- });
4578
- return;
4579
- }
4580
-
4581
- if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
4582
- }
4583
-
4584
- this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
4585
- }
4586
-
4587
- /**
4588
- * Upgrade the connection to WebSocket.
4589
- *
4590
- * @param {Object} extensions The accepted extensions
4591
- * @param {String} key The value of the `Sec-WebSocket-Key` header
4592
- * @param {Set} protocols The subprotocols
4593
- * @param {http.IncomingMessage} req The request object
4594
- * @param {Duplex} socket The network socket between the server and client
4595
- * @param {Buffer} head The first packet of the upgraded stream
4596
- * @param {Function} cb Callback
4597
- * @throws {Error} If called more than once with the same socket
4598
- * @private
4599
- */
4600
- completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
4601
- //
4602
- // Destroy the socket if the client has already sent a FIN packet.
4603
- //
4604
- if (!socket.readable || !socket.writable) return socket.destroy();
4605
-
4606
- if (socket[kWebSocket]) {
4607
- throw new Error(
4608
- 'server.handleUpgrade() was called more than once with the same ' +
4609
- 'socket, possibly due to a misconfiguration'
4610
- );
4611
- }
4612
-
4613
- if (this._state > RUNNING) return abortHandshake(socket, 503);
4614
-
4615
- const digest = createHash('sha1')
4616
- .update(key + GUID)
4617
- .digest('base64');
4618
-
4619
- const headers = [
4620
- 'HTTP/1.1 101 Switching Protocols',
4621
- 'Upgrade: websocket',
4622
- 'Connection: Upgrade',
4623
- `Sec-WebSocket-Accept: ${digest}`
4624
- ];
4625
-
4626
- const ws = new this.options.WebSocket(null, undefined, this.options);
4627
-
4628
- if (protocols.size) {
4629
- //
4630
- // Optionally call external protocol selection handler.
4631
- //
4632
- const protocol = this.options.handleProtocols
4633
- ? this.options.handleProtocols(protocols, req)
4634
- : protocols.values().next().value;
4635
-
4636
- if (protocol) {
4637
- headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
4638
- ws._protocol = protocol;
4639
- }
4640
- }
4641
-
4642
- if (extensions[PerMessageDeflate.extensionName]) {
4643
- const params = extensions[PerMessageDeflate.extensionName].params;
4644
- const value = extension.format({
4645
- [PerMessageDeflate.extensionName]: [params]
4646
- });
4647
- headers.push(`Sec-WebSocket-Extensions: ${value}`);
4648
- ws._extensions = extensions;
4649
- }
4650
-
4651
- //
4652
- // Allow external modification/inspection of handshake headers.
4653
- //
4654
- this.emit('headers', headers, req);
4655
-
4656
- socket.write(headers.concat('\r\n').join('\r\n'));
4657
- socket.removeListener('error', socketOnError);
4658
-
4659
- ws.setSocket(socket, head, {
4660
- allowSynchronousEvents: this.options.allowSynchronousEvents,
4661
- maxPayload: this.options.maxPayload,
4662
- skipUTF8Validation: this.options.skipUTF8Validation
4663
- });
4664
-
4665
- if (this.clients) {
4666
- this.clients.add(ws);
4667
- ws.on('close', () => {
4668
- this.clients.delete(ws);
4669
-
4670
- if (this._shouldEmitClose && !this.clients.size) {
4671
- process.nextTick(emitClose, this);
4672
- }
4673
- });
4674
- }
4675
-
4676
- cb(ws, req);
4677
- }
4678
- }
4679
-
4680
- websocketServer = WebSocketServer;
4681
-
4682
- /**
4683
- * Add event listeners on an `EventEmitter` using a map of <event, listener>
4684
- * pairs.
4685
- *
4686
- * @param {EventEmitter} server The event emitter
4687
- * @param {Object.<String, Function>} map The listeners to add
4688
- * @return {Function} A function that will remove the added listeners when
4689
- * called
4690
- * @private
4691
- */
4692
- function addListeners(server, map) {
4693
- for (const event of Object.keys(map)) server.on(event, map[event]);
4694
-
4695
- return function removeListeners() {
4696
- for (const event of Object.keys(map)) {
4697
- server.removeListener(event, map[event]);
4698
- }
4699
- };
4700
- }
4701
-
4702
- /**
4703
- * Emit a `'close'` event on an `EventEmitter`.
4704
- *
4705
- * @param {EventEmitter} server The event emitter
4706
- * @private
4707
- */
4708
- function emitClose(server) {
4709
- server._state = CLOSED;
4710
- server.emit('close');
4711
- }
4712
-
4713
- /**
4714
- * Handle socket errors.
4715
- *
4716
- * @private
4717
- */
4718
- function socketOnError() {
4719
- this.destroy();
4720
- }
4721
-
4722
- /**
4723
- * Close the connection when preconditions are not fulfilled.
4724
- *
4725
- * @param {Duplex} socket The socket of the upgrade request
4726
- * @param {Number} code The HTTP response status code
4727
- * @param {String} [message] The HTTP response body
4728
- * @param {Object} [headers] Additional HTTP response headers
4729
- * @private
4730
- */
4731
- function abortHandshake(socket, code, message, headers) {
4732
- //
4733
- // The socket is writable unless the user destroyed or ended it before calling
4734
- // `server.handleUpgrade()` or in the `verifyClient` function, which is a user
4735
- // error. Handling this does not make much sense as the worst that can happen
4736
- // is that some of the data written by the user might be discarded due to the
4737
- // call to `socket.end()` below, which triggers an `'error'` event that in
4738
- // turn causes the socket to be destroyed.
4739
- //
4740
- message = message || http.STATUS_CODES[code];
4741
- headers = {
4742
- Connection: 'close',
4743
- 'Content-Type': 'text/html',
4744
- 'Content-Length': Buffer.byteLength(message),
4745
- ...headers
4746
- };
4747
-
4748
- socket.once('finish', socket.destroy);
4749
-
4750
- socket.end(
4751
- `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
4752
- Object.keys(headers)
4753
- .map((h) => `${h}: ${headers[h]}`)
4754
- .join('\r\n') +
4755
- '\r\n\r\n' +
4756
- message
4757
- );
4758
- }
4759
-
4760
- /**
4761
- * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
4762
- * one listener for it, otherwise call `abortHandshake()`.
4763
- *
4764
- * @param {WebSocketServer} server The WebSocket server
4765
- * @param {http.IncomingMessage} req The request object
4766
- * @param {Duplex} socket The socket of the upgrade request
4767
- * @param {Number} code The HTTP response status code
4768
- * @param {String} message The HTTP response body
4769
- * @private
4770
- */
4771
- function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) {
4772
- if (server.listenerCount('wsClientError')) {
4773
- const err = new Error(message);
4774
- Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
4775
-
4776
- server.emit('wsClientError', err, socket, req);
4777
- } else {
4778
- abortHandshake(socket, code, message);
4779
- }
4780
- }
4781
- return websocketServer;
4782
- }
4783
-
4784
- requireWebsocketServer();
4785
-
4786
- // Ignoring missing types error to avoid adding another dependency for this hack to work
4787
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
4788
- const customGlobal = global;
4789
- // These things must exist before importing `react-devtools-core`
4790
- customGlobal.WebSocket ||= WebSocket;
4791
- customGlobal.window ||= global;
4792
- customGlobal.self ||= global;
4793
- // Filter out Ink's internal components from devtools for a cleaner view.
4794
- // Also, ince `react-devtools-shared` package isn't published on npm, we can't
4795
- // use its types, that's why there are hard-coded values in `type` fields below.
4796
- // See https://github.com/facebook/react/blob/edf6eac8a181860fd8a2d076a43806f1237495a1/packages/react-devtools-shared/src/types.js#L24
4797
- customGlobal.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = [
4798
- {
4799
- // ComponentFilterElementType
4800
- type: 1,
4801
- // ElementTypeHostComponent
4802
- value: 7,
4803
- isEnabled: true,
4804
- },
4805
- {
4806
- // ComponentFilterDisplayName
4807
- type: 2,
4808
- value: 'InternalApp',
4809
- isEnabled: true,
4810
- isValid: true,
4811
- },
4812
- {
4813
- // ComponentFilterDisplayName
4814
- type: 2,
4815
- value: 'InternalAppContext',
4816
- isEnabled: true,
4817
- isValid: true,
4818
- },
4819
- {
4820
- // ComponentFilterDisplayName
4821
- type: 2,
4822
- value: 'InternalStdoutContext',
4823
- isEnabled: true,
4824
- isValid: true,
4825
- },
4826
- {
4827
- // ComponentFilterDisplayName
4828
- type: 2,
4829
- value: 'InternalStderrContext',
4830
- isEnabled: true,
4831
- isValid: true,
4832
- },
4833
- {
4834
- // ComponentFilterDisplayName
4835
- type: 2,
4836
- value: 'InternalStdinContext',
4837
- isEnabled: true,
4838
- isValid: true,
4839
- },
4840
- {
4841
- // ComponentFilterDisplayName
4842
- type: 2,
4843
- value: 'InternalFocusContext',
4844
- isEnabled: true,
4845
- isValid: true,
4846
- },
4847
- ];
4848
-
4849
- /* eslint-disable import/order */
4850
- // eslint-disable-next-line import/no-unassigned-import
4851
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
4852
- devtools.connectToDevTools();