[SignalingServer] Optimize dependent modules
[platform/framework/web/wrtjs.git] / signaling_server / service / node_modules / engine.io-client / node_modules / ws / lib / websocket.js
1 'use strict';
2
3 const EventEmitter = require('events');
4 const https = require('https');
5 const http = require('http');
6 const net = require('net');
7 const tls = require('tls');
8 const { randomBytes, createHash } = require('crypto');
9 const { URL } = require('url');
10
11 const PerMessageDeflate = require('./permessage-deflate');
12 const Receiver = require('./receiver');
13 const Sender = require('./sender');
14 const {
15   BINARY_TYPES,
16   EMPTY_BUFFER,
17   GUID,
18   kStatusCode,
19   kWebSocket,
20   NOOP
21 } = require('./constants');
22 const { addEventListener, removeEventListener } = require('./event-target');
23 const { format, parse } = require('./extension');
24 const { toBuffer } = require('./buffer-util');
25
26 const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
27 const protocolVersions = [8, 13];
28 const closeTimeout = 30 * 1000;
29
30 /**
31  * Class representing a WebSocket.
32  *
33  * @extends EventEmitter
34  */
35 class WebSocket extends EventEmitter {
36   /**
37    * Create a new `WebSocket`.
38    *
39    * @param {(String|url.URL)} address The URL to which to connect
40    * @param {(String|String[])} [protocols] The subprotocols
41    * @param {Object} [options] Connection options
42    */
43   constructor(address, protocols, options) {
44     super();
45
46     this._binaryType = BINARY_TYPES[0];
47     this._closeCode = 1006;
48     this._closeFrameReceived = false;
49     this._closeFrameSent = false;
50     this._closeMessage = '';
51     this._closeTimer = null;
52     this._extensions = {};
53     this._protocol = '';
54     this._readyState = WebSocket.CONNECTING;
55     this._receiver = null;
56     this._sender = null;
57     this._socket = null;
58
59     if (address !== null) {
60       this._bufferedAmount = 0;
61       this._isServer = false;
62       this._redirects = 0;
63
64       if (Array.isArray(protocols)) {
65         protocols = protocols.join(', ');
66       } else if (typeof protocols === 'object' && protocols !== null) {
67         options = protocols;
68         protocols = undefined;
69       }
70
71       initAsClient(this, address, protocols, options);
72     } else {
73       this._isServer = true;
74     }
75   }
76
77   /**
78    * This deviates from the WHATWG interface since ws doesn't support the
79    * required default "blob" type (instead we define a custom "nodebuffer"
80    * type).
81    *
82    * @type {String}
83    */
84   get binaryType() {
85     return this._binaryType;
86   }
87
88   set binaryType(type) {
89     if (!BINARY_TYPES.includes(type)) return;
90
91     this._binaryType = type;
92
93     //
94     // Allow to change `binaryType` on the fly.
95     //
96     if (this._receiver) this._receiver._binaryType = type;
97   }
98
99   /**
100    * @type {Number}
101    */
102   get bufferedAmount() {
103     if (!this._socket) return this._bufferedAmount;
104
105     return this._socket._writableState.length + this._sender._bufferedBytes;
106   }
107
108   /**
109    * @type {String}
110    */
111   get extensions() {
112     return Object.keys(this._extensions).join();
113   }
114
115   /**
116    * @type {String}
117    */
118   get protocol() {
119     return this._protocol;
120   }
121
122   /**
123    * @type {Number}
124    */
125   get readyState() {
126     return this._readyState;
127   }
128
129   /**
130    * @type {String}
131    */
132   get url() {
133     return this._url;
134   }
135
136   /**
137    * Set up the socket and the internal resources.
138    *
139    * @param {net.Socket} socket The network socket between the server and client
140    * @param {Buffer} head The first packet of the upgraded stream
141    * @param {Number} [maxPayload=0] The maximum allowed message size
142    * @private
143    */
144   setSocket(socket, head, maxPayload) {
145     const receiver = new Receiver(
146       this.binaryType,
147       this._extensions,
148       this._isServer,
149       maxPayload
150     );
151
152     this._sender = new Sender(socket, this._extensions);
153     this._receiver = receiver;
154     this._socket = socket;
155
156     receiver[kWebSocket] = this;
157     socket[kWebSocket] = this;
158
159     receiver.on('conclude', receiverOnConclude);
160     receiver.on('drain', receiverOnDrain);
161     receiver.on('error', receiverOnError);
162     receiver.on('message', receiverOnMessage);
163     receiver.on('ping', receiverOnPing);
164     receiver.on('pong', receiverOnPong);
165
166     socket.setTimeout(0);
167     socket.setNoDelay();
168
169     if (head.length > 0) socket.unshift(head);
170
171     socket.on('close', socketOnClose);
172     socket.on('data', socketOnData);
173     socket.on('end', socketOnEnd);
174     socket.on('error', socketOnError);
175
176     this._readyState = WebSocket.OPEN;
177     this.emit('open');
178   }
179
180   /**
181    * Emit the `'close'` event.
182    *
183    * @private
184    */
185   emitClose() {
186     if (!this._socket) {
187       this._readyState = WebSocket.CLOSED;
188       this.emit('close', this._closeCode, this._closeMessage);
189       return;
190     }
191
192     if (this._extensions[PerMessageDeflate.extensionName]) {
193       this._extensions[PerMessageDeflate.extensionName].cleanup();
194     }
195
196     this._receiver.removeAllListeners();
197     this._readyState = WebSocket.CLOSED;
198     this.emit('close', this._closeCode, this._closeMessage);
199   }
200
201   /**
202    * Start a closing handshake.
203    *
204    *          +----------+   +-----------+   +----------+
205    *     - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
206    *    |     +----------+   +-----------+   +----------+     |
207    *          +----------+   +-----------+         |
208    * CLOSING  |ws.close()|<--|close frame|<--+-----+       CLOSING
209    *          +----------+   +-----------+   |
210    *    |           |                        |   +---+        |
211    *                +------------------------+-->|fin| - - - -
212    *    |         +---+                      |   +---+
213    *     - - - - -|fin|<---------------------+
214    *              +---+
215    *
216    * @param {Number} [code] Status code explaining why the connection is closing
217    * @param {String} [data] A string explaining why the connection is closing
218    * @public
219    */
220   close(code, data) {
221     if (this.readyState === WebSocket.CLOSED) return;
222     if (this.readyState === WebSocket.CONNECTING) {
223       const msg = 'WebSocket was closed before the connection was established';
224       return abortHandshake(this, this._req, msg);
225     }
226
227     if (this.readyState === WebSocket.CLOSING) {
228       if (this._closeFrameSent && this._closeFrameReceived) this._socket.end();
229       return;
230     }
231
232     this._readyState = WebSocket.CLOSING;
233     this._sender.close(code, data, !this._isServer, (err) => {
234       //
235       // This error is handled by the `'error'` listener on the socket. We only
236       // want to know if the close frame has been sent here.
237       //
238       if (err) return;
239
240       this._closeFrameSent = true;
241       if (this._closeFrameReceived) this._socket.end();
242     });
243
244     //
245     // Specify a timeout for the closing handshake to complete.
246     //
247     this._closeTimer = setTimeout(
248       this._socket.destroy.bind(this._socket),
249       closeTimeout
250     );
251   }
252
253   /**
254    * Send a ping.
255    *
256    * @param {*} [data] The data to send
257    * @param {Boolean} [mask] Indicates whether or not to mask `data`
258    * @param {Function} [cb] Callback which is executed when the ping is sent
259    * @public
260    */
261   ping(data, mask, cb) {
262     if (this.readyState === WebSocket.CONNECTING) {
263       throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
264     }
265
266     if (typeof data === 'function') {
267       cb = data;
268       data = mask = undefined;
269     } else if (typeof mask === 'function') {
270       cb = mask;
271       mask = undefined;
272     }
273
274     if (typeof data === 'number') data = data.toString();
275
276     if (this.readyState !== WebSocket.OPEN) {
277       sendAfterClose(this, data, cb);
278       return;
279     }
280
281     if (mask === undefined) mask = !this._isServer;
282     this._sender.ping(data || EMPTY_BUFFER, mask, cb);
283   }
284
285   /**
286    * Send a pong.
287    *
288    * @param {*} [data] The data to send
289    * @param {Boolean} [mask] Indicates whether or not to mask `data`
290    * @param {Function} [cb] Callback which is executed when the pong is sent
291    * @public
292    */
293   pong(data, mask, cb) {
294     if (this.readyState === WebSocket.CONNECTING) {
295       throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
296     }
297
298     if (typeof data === 'function') {
299       cb = data;
300       data = mask = undefined;
301     } else if (typeof mask === 'function') {
302       cb = mask;
303       mask = undefined;
304     }
305
306     if (typeof data === 'number') data = data.toString();
307
308     if (this.readyState !== WebSocket.OPEN) {
309       sendAfterClose(this, data, cb);
310       return;
311     }
312
313     if (mask === undefined) mask = !this._isServer;
314     this._sender.pong(data || EMPTY_BUFFER, mask, cb);
315   }
316
317   /**
318    * Send a data message.
319    *
320    * @param {*} data The message to send
321    * @param {Object} [options] Options object
322    * @param {Boolean} [options.compress] Specifies whether or not to compress
323    *     `data`
324    * @param {Boolean} [options.binary] Specifies whether `data` is binary or
325    *     text
326    * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
327    *     last one
328    * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
329    * @param {Function} [cb] Callback which is executed when data is written out
330    * @public
331    */
332   send(data, options, cb) {
333     if (this.readyState === WebSocket.CONNECTING) {
334       throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
335     }
336
337     if (typeof options === 'function') {
338       cb = options;
339       options = {};
340     }
341
342     if (typeof data === 'number') data = data.toString();
343
344     if (this.readyState !== WebSocket.OPEN) {
345       sendAfterClose(this, data, cb);
346       return;
347     }
348
349     const opts = {
350       binary: typeof data !== 'string',
351       mask: !this._isServer,
352       compress: true,
353       fin: true,
354       ...options
355     };
356
357     if (!this._extensions[PerMessageDeflate.extensionName]) {
358       opts.compress = false;
359     }
360
361     this._sender.send(data || EMPTY_BUFFER, opts, cb);
362   }
363
364   /**
365    * Forcibly close the connection.
366    *
367    * @public
368    */
369   terminate() {
370     if (this.readyState === WebSocket.CLOSED) return;
371     if (this.readyState === WebSocket.CONNECTING) {
372       const msg = 'WebSocket was closed before the connection was established';
373       return abortHandshake(this, this._req, msg);
374     }
375
376     if (this._socket) {
377       this._readyState = WebSocket.CLOSING;
378       this._socket.destroy();
379     }
380   }
381 }
382
383 readyStates.forEach((readyState, i) => {
384   const descriptor = { enumerable: true, value: i };
385
386   Object.defineProperty(WebSocket.prototype, readyState, descriptor);
387   Object.defineProperty(WebSocket, readyState, descriptor);
388 });
389
390 [
391   'binaryType',
392   'bufferedAmount',
393   'extensions',
394   'protocol',
395   'readyState',
396   'url'
397 ].forEach((property) => {
398   Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
399 });
400
401 //
402 // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
403 // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
404 //
405 ['open', 'error', 'close', 'message'].forEach((method) => {
406   Object.defineProperty(WebSocket.prototype, `on${method}`, {
407     configurable: true,
408     enumerable: true,
409     /**
410      * Return the listener of the event.
411      *
412      * @return {(Function|undefined)} The event listener or `undefined`
413      * @public
414      */
415     get() {
416       const listeners = this.listeners(method);
417       for (let i = 0; i < listeners.length; i++) {
418         if (listeners[i]._listener) return listeners[i]._listener;
419       }
420
421       return undefined;
422     },
423     /**
424      * Add a listener for the event.
425      *
426      * @param {Function} listener The listener to add
427      * @public
428      */
429     set(listener) {
430       const listeners = this.listeners(method);
431       for (let i = 0; i < listeners.length; i++) {
432         //
433         // Remove only the listeners added via `addEventListener`.
434         //
435         if (listeners[i]._listener) this.removeListener(method, listeners[i]);
436       }
437       this.addEventListener(method, listener);
438     }
439   });
440 });
441
442 WebSocket.prototype.addEventListener = addEventListener;
443 WebSocket.prototype.removeEventListener = removeEventListener;
444
445 module.exports = WebSocket;
446
447 /**
448  * Initialize a WebSocket client.
449  *
450  * @param {WebSocket} websocket The client to initialize
451  * @param {(String|url.URL)} address The URL to which to connect
452  * @param {String} [protocols] The subprotocols
453  * @param {Object} [options] Connection options
454  * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
455  *     permessage-deflate
456  * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
457  *     handshake request
458  * @param {Number} [options.protocolVersion=13] Value of the
459  *     `Sec-WebSocket-Version` header
460  * @param {String} [options.origin] Value of the `Origin` or
461  *     `Sec-WebSocket-Origin` header
462  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
463  *     size
464  * @param {Boolean} [options.followRedirects=false] Whether or not to follow
465  *     redirects
466  * @param {Number} [options.maxRedirects=10] The maximum number of redirects
467  *     allowed
468  * @private
469  */
470 function initAsClient(websocket, address, protocols, options) {
471   const opts = {
472     protocolVersion: protocolVersions[1],
473     maxPayload: 100 * 1024 * 1024,
474     perMessageDeflate: true,
475     followRedirects: false,
476     maxRedirects: 10,
477     ...options,
478     createConnection: undefined,
479     socketPath: undefined,
480     hostname: undefined,
481     protocol: undefined,
482     timeout: undefined,
483     method: undefined,
484     host: undefined,
485     path: undefined,
486     port: undefined
487   };
488
489   if (!protocolVersions.includes(opts.protocolVersion)) {
490     throw new RangeError(
491       `Unsupported protocol version: ${opts.protocolVersion} ` +
492         `(supported versions: ${protocolVersions.join(', ')})`
493     );
494   }
495
496   let parsedUrl;
497
498   if (address instanceof URL) {
499     parsedUrl = address;
500     websocket._url = address.href;
501   } else {
502     parsedUrl = new URL(address);
503     websocket._url = address;
504   }
505
506   const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
507
508   if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) {
509     throw new Error(`Invalid URL: ${websocket.url}`);
510   }
511
512   const isSecure =
513     parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:';
514   const defaultPort = isSecure ? 443 : 80;
515   const key = randomBytes(16).toString('base64');
516   const get = isSecure ? https.get : http.get;
517   let perMessageDeflate;
518
519   opts.createConnection = isSecure ? tlsConnect : netConnect;
520   opts.defaultPort = opts.defaultPort || defaultPort;
521   opts.port = parsedUrl.port || defaultPort;
522   opts.host = parsedUrl.hostname.startsWith('[')
523     ? parsedUrl.hostname.slice(1, -1)
524     : parsedUrl.hostname;
525   opts.headers = {
526     'Sec-WebSocket-Version': opts.protocolVersion,
527     'Sec-WebSocket-Key': key,
528     Connection: 'Upgrade',
529     Upgrade: 'websocket',
530     ...opts.headers
531   };
532   opts.path = parsedUrl.pathname + parsedUrl.search;
533   opts.timeout = opts.handshakeTimeout;
534
535   if (opts.perMessageDeflate) {
536     perMessageDeflate = new PerMessageDeflate(
537       opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
538       false,
539       opts.maxPayload
540     );
541     opts.headers['Sec-WebSocket-Extensions'] = format({
542       [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
543     });
544   }
545   if (protocols) {
546     opts.headers['Sec-WebSocket-Protocol'] = protocols;
547   }
548   if (opts.origin) {
549     if (opts.protocolVersion < 13) {
550       opts.headers['Sec-WebSocket-Origin'] = opts.origin;
551     } else {
552       opts.headers.Origin = opts.origin;
553     }
554   }
555   if (parsedUrl.username || parsedUrl.password) {
556     opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
557   }
558
559   if (isUnixSocket) {
560     const parts = opts.path.split(':');
561
562     opts.socketPath = parts[0];
563     opts.path = parts[1];
564   }
565
566   let req = (websocket._req = get(opts));
567
568   if (opts.timeout) {
569     req.on('timeout', () => {
570       abortHandshake(websocket, req, 'Opening handshake has timed out');
571     });
572   }
573
574   req.on('error', (err) => {
575     if (req === null || req.aborted) return;
576
577     req = websocket._req = null;
578     websocket._readyState = WebSocket.CLOSING;
579     websocket.emit('error', err);
580     websocket.emitClose();
581   });
582
583   req.on('response', (res) => {
584     const location = res.headers.location;
585     const statusCode = res.statusCode;
586
587     if (
588       location &&
589       opts.followRedirects &&
590       statusCode >= 300 &&
591       statusCode < 400
592     ) {
593       if (++websocket._redirects > opts.maxRedirects) {
594         abortHandshake(websocket, req, 'Maximum redirects exceeded');
595         return;
596       }
597
598       req.abort();
599
600       const addr = new URL(location, address);
601
602       initAsClient(websocket, addr, protocols, options);
603     } else if (!websocket.emit('unexpected-response', req, res)) {
604       abortHandshake(
605         websocket,
606         req,
607         `Unexpected server response: ${res.statusCode}`
608       );
609     }
610   });
611
612   req.on('upgrade', (res, socket, head) => {
613     websocket.emit('upgrade', res);
614
615     //
616     // The user may have closed the connection from a listener of the `upgrade`
617     // event.
618     //
619     if (websocket.readyState !== WebSocket.CONNECTING) return;
620
621     req = websocket._req = null;
622
623     const digest = createHash('sha1')
624       .update(key + GUID)
625       .digest('base64');
626
627     if (res.headers['sec-websocket-accept'] !== digest) {
628       abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
629       return;
630     }
631
632     const serverProt = res.headers['sec-websocket-protocol'];
633     const protList = (protocols || '').split(/, */);
634     let protError;
635
636     if (!protocols && serverProt) {
637       protError = 'Server sent a subprotocol but none was requested';
638     } else if (protocols && !serverProt) {
639       protError = 'Server sent no subprotocol';
640     } else if (serverProt && !protList.includes(serverProt)) {
641       protError = 'Server sent an invalid subprotocol';
642     }
643
644     if (protError) {
645       abortHandshake(websocket, socket, protError);
646       return;
647     }
648
649     if (serverProt) websocket._protocol = serverProt;
650
651     if (perMessageDeflate) {
652       try {
653         const extensions = parse(res.headers['sec-websocket-extensions']);
654
655         if (extensions[PerMessageDeflate.extensionName]) {
656           perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
657           websocket._extensions[
658             PerMessageDeflate.extensionName
659           ] = perMessageDeflate;
660         }
661       } catch (err) {
662         abortHandshake(
663           websocket,
664           socket,
665           'Invalid Sec-WebSocket-Extensions header'
666         );
667         return;
668       }
669     }
670
671     websocket.setSocket(socket, head, opts.maxPayload);
672   });
673 }
674
675 /**
676  * Create a `net.Socket` and initiate a connection.
677  *
678  * @param {Object} options Connection options
679  * @return {net.Socket} The newly created socket used to start the connection
680  * @private
681  */
682 function netConnect(options) {
683   options.path = options.socketPath;
684   return net.connect(options);
685 }
686
687 /**
688  * Create a `tls.TLSSocket` and initiate a connection.
689  *
690  * @param {Object} options Connection options
691  * @return {tls.TLSSocket} The newly created socket used to start the connection
692  * @private
693  */
694 function tlsConnect(options) {
695   options.path = undefined;
696
697   if (!options.servername && options.servername !== '') {
698     options.servername = net.isIP(options.host) ? '' : options.host;
699   }
700
701   return tls.connect(options);
702 }
703
704 /**
705  * Abort the handshake and emit an error.
706  *
707  * @param {WebSocket} websocket The WebSocket instance
708  * @param {(http.ClientRequest|net.Socket)} stream The request to abort or the
709  *     socket to destroy
710  * @param {String} message The error message
711  * @private
712  */
713 function abortHandshake(websocket, stream, message) {
714   websocket._readyState = WebSocket.CLOSING;
715
716   const err = new Error(message);
717   Error.captureStackTrace(err, abortHandshake);
718
719   if (stream.setHeader) {
720     stream.abort();
721     stream.once('abort', websocket.emitClose.bind(websocket));
722     websocket.emit('error', err);
723   } else {
724     stream.destroy(err);
725     stream.once('error', websocket.emit.bind(websocket, 'error'));
726     stream.once('close', websocket.emitClose.bind(websocket));
727   }
728 }
729
730 /**
731  * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
732  * when the `readyState` attribute is `CLOSING` or `CLOSED`.
733  *
734  * @param {WebSocket} websocket The WebSocket instance
735  * @param {*} [data] The data to send
736  * @param {Function} [cb] Callback
737  * @private
738  */
739 function sendAfterClose(websocket, data, cb) {
740   if (data) {
741     const length = toBuffer(data).length;
742
743     //
744     // The `_bufferedAmount` property is used only when the peer is a client and
745     // the opening handshake fails. Under these circumstances, in fact, the
746     // `setSocket()` method is not called, so the `_socket` and `_sender`
747     // properties are set to `null`.
748     //
749     if (websocket._socket) websocket._sender._bufferedBytes += length;
750     else websocket._bufferedAmount += length;
751   }
752
753   if (cb) {
754     const err = new Error(
755       `WebSocket is not open: readyState ${websocket.readyState} ` +
756         `(${readyStates[websocket.readyState]})`
757     );
758     cb(err);
759   }
760 }
761
762 /**
763  * The listener of the `Receiver` `'conclude'` event.
764  *
765  * @param {Number} code The status code
766  * @param {String} reason The reason for closing
767  * @private
768  */
769 function receiverOnConclude(code, reason) {
770   const websocket = this[kWebSocket];
771
772   websocket._socket.removeListener('data', socketOnData);
773   websocket._socket.resume();
774
775   websocket._closeFrameReceived = true;
776   websocket._closeMessage = reason;
777   websocket._closeCode = code;
778
779   if (code === 1005) websocket.close();
780   else websocket.close(code, reason);
781 }
782
783 /**
784  * The listener of the `Receiver` `'drain'` event.
785  *
786  * @private
787  */
788 function receiverOnDrain() {
789   this[kWebSocket]._socket.resume();
790 }
791
792 /**
793  * The listener of the `Receiver` `'error'` event.
794  *
795  * @param {(RangeError|Error)} err The emitted error
796  * @private
797  */
798 function receiverOnError(err) {
799   const websocket = this[kWebSocket];
800
801   websocket._socket.removeListener('data', socketOnData);
802
803   websocket._readyState = WebSocket.CLOSING;
804   websocket._closeCode = err[kStatusCode];
805   websocket.emit('error', err);
806   websocket._socket.destroy();
807 }
808
809 /**
810  * The listener of the `Receiver` `'finish'` event.
811  *
812  * @private
813  */
814 function receiverOnFinish() {
815   this[kWebSocket].emitClose();
816 }
817
818 /**
819  * The listener of the `Receiver` `'message'` event.
820  *
821  * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The message
822  * @private
823  */
824 function receiverOnMessage(data) {
825   this[kWebSocket].emit('message', data);
826 }
827
828 /**
829  * The listener of the `Receiver` `'ping'` event.
830  *
831  * @param {Buffer} data The data included in the ping frame
832  * @private
833  */
834 function receiverOnPing(data) {
835   const websocket = this[kWebSocket];
836
837   websocket.pong(data, !websocket._isServer, NOOP);
838   websocket.emit('ping', data);
839 }
840
841 /**
842  * The listener of the `Receiver` `'pong'` event.
843  *
844  * @param {Buffer} data The data included in the pong frame
845  * @private
846  */
847 function receiverOnPong(data) {
848   this[kWebSocket].emit('pong', data);
849 }
850
851 /**
852  * The listener of the `net.Socket` `'close'` event.
853  *
854  * @private
855  */
856 function socketOnClose() {
857   const websocket = this[kWebSocket];
858
859   this.removeListener('close', socketOnClose);
860   this.removeListener('end', socketOnEnd);
861
862   websocket._readyState = WebSocket.CLOSING;
863
864   //
865   // The close frame might not have been received or the `'end'` event emitted,
866   // for example, if the socket was destroyed due to an error. Ensure that the
867   // `receiver` stream is closed after writing any remaining buffered data to
868   // it. If the readable side of the socket is in flowing mode then there is no
869   // buffered data as everything has been already written and `readable.read()`
870   // will return `null`. If instead, the socket is paused, any possible buffered
871   // data will be read as a single chunk and emitted synchronously in a single
872   // `'data'` event.
873   //
874   websocket._socket.read();
875   websocket._receiver.end();
876
877   this.removeListener('data', socketOnData);
878   this[kWebSocket] = undefined;
879
880   clearTimeout(websocket._closeTimer);
881
882   if (
883     websocket._receiver._writableState.finished ||
884     websocket._receiver._writableState.errorEmitted
885   ) {
886     websocket.emitClose();
887   } else {
888     websocket._receiver.on('error', receiverOnFinish);
889     websocket._receiver.on('finish', receiverOnFinish);
890   }
891 }
892
893 /**
894  * The listener of the `net.Socket` `'data'` event.
895  *
896  * @param {Buffer} chunk A chunk of data
897  * @private
898  */
899 function socketOnData(chunk) {
900   if (!this[kWebSocket]._receiver.write(chunk)) {
901     this.pause();
902   }
903 }
904
905 /**
906  * The listener of the `net.Socket` `'end'` event.
907  *
908  * @private
909  */
910 function socketOnEnd() {
911   const websocket = this[kWebSocket];
912
913   websocket._readyState = WebSocket.CLOSING;
914   websocket._receiver.end();
915   this.end();
916 }
917
918 /**
919  * The listener of the `net.Socket` `'error'` event.
920  *
921  * @private
922  */
923 function socketOnError() {
924   const websocket = this[kWebSocket];
925
926   this.removeListener('error', socketOnError);
927   this.on('error', NOOP);
928
929   if (websocket) {
930     websocket._readyState = WebSocket.CLOSING;
931     this.destroy();
932   }
933 }