websocket.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. 'use strict';
  2. const EventEmitter = require('events');
  3. const crypto = require('crypto');
  4. const https = require('https');
  5. const http = require('http');
  6. const net = require('net');
  7. const tls = require('tls');
  8. const url = require('url');
  9. const PerMessageDeflate = require('./permessage-deflate');
  10. const EventTarget = require('./event-target');
  11. const extension = require('./extension');
  12. const constants = require('./constants');
  13. const Receiver = require('./receiver');
  14. const Sender = require('./sender');
  15. const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
  16. const kWebSocket = constants.kWebSocket;
  17. const protocolVersions = [8, 13];
  18. const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly.
  19. /**
  20. * Class representing a WebSocket.
  21. *
  22. * @extends EventEmitter
  23. */
  24. class WebSocket extends EventEmitter {
  25. /**
  26. * Create a new `WebSocket`.
  27. *
  28. * @param {(String|url.Url|url.URL)} address The URL to which to connect
  29. * @param {(String|String[])} protocols The subprotocols
  30. * @param {Object} options Connection options
  31. */
  32. constructor (address, protocols, options) {
  33. super();
  34. this.readyState = WebSocket.CONNECTING;
  35. this.protocol = '';
  36. this._binaryType = constants.BINARY_TYPES[0];
  37. this._closeFrameReceived = false;
  38. this._closeFrameSent = false;
  39. this._closeMessage = '';
  40. this._closeTimer = null;
  41. this._closeCode = 1006;
  42. this._extensions = {};
  43. this._isServer = true;
  44. this._receiver = null;
  45. this._sender = null;
  46. this._socket = null;
  47. if (address !== null) {
  48. if (Array.isArray(protocols)) {
  49. protocols = protocols.join(', ');
  50. } else if (typeof protocols === 'object' && protocols !== null) {
  51. options = protocols;
  52. protocols = undefined;
  53. }
  54. initAsClient.call(this, address, protocols, options);
  55. }
  56. }
  57. get CONNECTING () { return WebSocket.CONNECTING; }
  58. get CLOSING () { return WebSocket.CLOSING; }
  59. get CLOSED () { return WebSocket.CLOSED; }
  60. get OPEN () { return WebSocket.OPEN; }
  61. /**
  62. * This deviates from the WHATWG interface since ws doesn't support the required
  63. * default "blob" type (instead we define a custom "nodebuffer" type).
  64. *
  65. * @type {String}
  66. */
  67. get binaryType () {
  68. return this._binaryType;
  69. }
  70. set binaryType (type) {
  71. if (constants.BINARY_TYPES.indexOf(type) < 0) return;
  72. this._binaryType = type;
  73. //
  74. // Allow to change `binaryType` on the fly.
  75. //
  76. if (this._receiver) this._receiver._binaryType = type;
  77. }
  78. /**
  79. * @type {Number}
  80. */
  81. get bufferedAmount () {
  82. if (!this._socket) return 0;
  83. //
  84. // `socket.bufferSize` is `undefined` if the socket is closed.
  85. //
  86. return (this._socket.bufferSize || 0) + this._sender._bufferedBytes;
  87. }
  88. /**
  89. * @type {String}
  90. */
  91. get extensions () {
  92. return Object.keys(this._extensions).join();
  93. }
  94. /**
  95. * Set up the socket and the internal resources.
  96. *
  97. * @param {net.Socket} socket The network socket between the server and client
  98. * @param {Buffer} head The first packet of the upgraded stream
  99. * @param {Number} maxPayload The maximum allowed message size
  100. * @private
  101. */
  102. setSocket (socket, head, maxPayload) {
  103. const receiver = new Receiver(
  104. this._binaryType,
  105. this._extensions,
  106. maxPayload
  107. );
  108. this._sender = new Sender(socket, this._extensions);
  109. this._receiver = receiver;
  110. this._socket = socket;
  111. receiver[kWebSocket] = this;
  112. socket[kWebSocket] = this;
  113. receiver.on('conclude', receiverOnConclude);
  114. receiver.on('drain', receiverOnDrain);
  115. receiver.on('error', receiverOnError);
  116. receiver.on('message', receiverOnMessage);
  117. receiver.on('ping', receiverOnPing);
  118. receiver.on('pong', receiverOnPong);
  119. socket.setTimeout(0);
  120. socket.setNoDelay();
  121. if (head.length > 0) socket.unshift(head);
  122. socket.on('close', socketOnClose);
  123. socket.on('data', socketOnData);
  124. socket.on('end', socketOnEnd);
  125. socket.on('error', socketOnError);
  126. this.readyState = WebSocket.OPEN;
  127. this.emit('open');
  128. }
  129. /**
  130. * Emit the `'close'` event.
  131. *
  132. * @private
  133. */
  134. emitClose () {
  135. this.readyState = WebSocket.CLOSED;
  136. if (!this._socket) {
  137. this.emit('close', this._closeCode, this._closeMessage);
  138. return;
  139. }
  140. if (this._extensions[PerMessageDeflate.extensionName]) {
  141. this._extensions[PerMessageDeflate.extensionName].cleanup();
  142. }
  143. this._receiver.removeAllListeners();
  144. this.emit('close', this._closeCode, this._closeMessage);
  145. }
  146. /**
  147. * Start a closing handshake.
  148. *
  149. * +----------+ +-----------+ +----------+
  150. * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
  151. * | +----------+ +-----------+ +----------+ |
  152. * +----------+ +-----------+ |
  153. * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
  154. * +----------+ +-----------+ |
  155. * | | | +---+ |
  156. * +------------------------+-->|fin| - - - -
  157. * | +---+ | +---+
  158. * - - - - -|fin|<---------------------+
  159. * +---+
  160. *
  161. * @param {Number} code Status code explaining why the connection is closing
  162. * @param {String} data A string explaining why the connection is closing
  163. * @public
  164. */
  165. close (code, data) {
  166. if (this.readyState === WebSocket.CLOSED) return;
  167. if (this.readyState === WebSocket.CONNECTING) {
  168. const msg = 'WebSocket was closed before the connection was established';
  169. return abortHandshake(this, this._req, msg);
  170. }
  171. if (this.readyState === WebSocket.CLOSING) {
  172. if (this._closeFrameSent && this._closeFrameReceived) this._socket.end();
  173. return;
  174. }
  175. this.readyState = WebSocket.CLOSING;
  176. this._sender.close(code, data, !this._isServer, (err) => {
  177. //
  178. // This error is handled by the `'error'` listener on the socket. We only
  179. // want to know if the close frame has been sent here.
  180. //
  181. if (err) return;
  182. this._closeFrameSent = true;
  183. if (this._socket.writable) {
  184. if (this._closeFrameReceived) this._socket.end();
  185. //
  186. // Ensure that the connection is closed even if the closing handshake
  187. // fails.
  188. //
  189. this._closeTimer = setTimeout(
  190. this._socket.destroy.bind(this._socket),
  191. closeTimeout
  192. );
  193. }
  194. });
  195. }
  196. /**
  197. * Send a ping.
  198. *
  199. * @param {*} data The data to send
  200. * @param {Boolean} mask Indicates whether or not to mask `data`
  201. * @param {Function} cb Callback which is executed when the ping is sent
  202. * @public
  203. */
  204. ping (data, mask, cb) {
  205. if (typeof data === 'function') {
  206. cb = data;
  207. data = mask = undefined;
  208. } else if (typeof mask === 'function') {
  209. cb = mask;
  210. mask = undefined;
  211. }
  212. if (this.readyState !== WebSocket.OPEN) {
  213. const err = new Error(
  214. `WebSocket is not open: readyState ${this.readyState} ` +
  215. `(${readyStates[this.readyState]})`
  216. );
  217. if (cb) return cb(err);
  218. throw err;
  219. }
  220. if (typeof data === 'number') data = data.toString();
  221. if (mask === undefined) mask = !this._isServer;
  222. this._sender.ping(data || constants.EMPTY_BUFFER, mask, cb);
  223. }
  224. /**
  225. * Send a pong.
  226. *
  227. * @param {*} data The data to send
  228. * @param {Boolean} mask Indicates whether or not to mask `data`
  229. * @param {Function} cb Callback which is executed when the pong is sent
  230. * @public
  231. */
  232. pong (data, mask, cb) {
  233. if (typeof data === 'function') {
  234. cb = data;
  235. data = mask = undefined;
  236. } else if (typeof mask === 'function') {
  237. cb = mask;
  238. mask = undefined;
  239. }
  240. if (this.readyState !== WebSocket.OPEN) {
  241. const err = new Error(
  242. `WebSocket is not open: readyState ${this.readyState} ` +
  243. `(${readyStates[this.readyState]})`
  244. );
  245. if (cb) return cb(err);
  246. throw err;
  247. }
  248. if (typeof data === 'number') data = data.toString();
  249. if (mask === undefined) mask = !this._isServer;
  250. this._sender.pong(data || constants.EMPTY_BUFFER, mask, cb);
  251. }
  252. /**
  253. * Send a data message.
  254. *
  255. * @param {*} data The message to send
  256. * @param {Object} options Options object
  257. * @param {Boolean} options.compress Specifies whether or not to compress `data`
  258. * @param {Boolean} options.binary Specifies whether `data` is binary or text
  259. * @param {Boolean} options.fin Specifies whether the fragment is the last one
  260. * @param {Boolean} options.mask Specifies whether or not to mask `data`
  261. * @param {Function} cb Callback which is executed when data is written out
  262. * @public
  263. */
  264. send (data, options, cb) {
  265. if (typeof options === 'function') {
  266. cb = options;
  267. options = {};
  268. }
  269. if (this.readyState !== WebSocket.OPEN) {
  270. const err = new Error(
  271. `WebSocket is not open: readyState ${this.readyState} ` +
  272. `(${readyStates[this.readyState]})`
  273. );
  274. if (cb) return cb(err);
  275. throw err;
  276. }
  277. if (typeof data === 'number') data = data.toString();
  278. const opts = Object.assign({
  279. binary: typeof data !== 'string',
  280. mask: !this._isServer,
  281. compress: true,
  282. fin: true
  283. }, options);
  284. if (!this._extensions[PerMessageDeflate.extensionName]) {
  285. opts.compress = false;
  286. }
  287. this._sender.send(data || constants.EMPTY_BUFFER, opts, cb);
  288. }
  289. /**
  290. * Forcibly close the connection.
  291. *
  292. * @public
  293. */
  294. terminate () {
  295. if (this.readyState === WebSocket.CLOSED) return;
  296. if (this.readyState === WebSocket.CONNECTING) {
  297. const msg = 'WebSocket was closed before the connection was established';
  298. return abortHandshake(this, this._req, msg);
  299. }
  300. if (this._socket) {
  301. this.readyState = WebSocket.CLOSING;
  302. this._socket.destroy();
  303. }
  304. }
  305. }
  306. readyStates.forEach((readyState, i) => {
  307. WebSocket[readyStates[i]] = i;
  308. });
  309. //
  310. // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
  311. // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
  312. //
  313. ['open', 'error', 'close', 'message'].forEach((method) => {
  314. Object.defineProperty(WebSocket.prototype, `on${method}`, {
  315. /**
  316. * Return the listener of the event.
  317. *
  318. * @return {(Function|undefined)} The event listener or `undefined`
  319. * @public
  320. */
  321. get () {
  322. const listeners = this.listeners(method);
  323. for (var i = 0; i < listeners.length; i++) {
  324. if (listeners[i]._listener) return listeners[i]._listener;
  325. }
  326. },
  327. /**
  328. * Add a listener for the event.
  329. *
  330. * @param {Function} listener The listener to add
  331. * @public
  332. */
  333. set (listener) {
  334. const listeners = this.listeners(method);
  335. for (var i = 0; i < listeners.length; i++) {
  336. //
  337. // Remove only the listeners added via `addEventListener`.
  338. //
  339. if (listeners[i]._listener) this.removeListener(method, listeners[i]);
  340. }
  341. this.addEventListener(method, listener);
  342. }
  343. });
  344. });
  345. WebSocket.prototype.addEventListener = EventTarget.addEventListener;
  346. WebSocket.prototype.removeEventListener = EventTarget.removeEventListener;
  347. module.exports = WebSocket;
  348. /**
  349. * Initialize a WebSocket client.
  350. *
  351. * @param {(String|url.Url|url.URL)} address The URL to which to connect
  352. * @param {String} protocols The subprotocols
  353. * @param {Object} options Connection options
  354. * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
  355. * @param {Number} options.handshakeTimeout Timeout in milliseconds for the handshake request
  356. * @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` header
  357. * @param {String} options.origin Value of the `Origin` or `Sec-WebSocket-Origin` header
  358. * @private
  359. */
  360. function initAsClient (address, protocols, options) {
  361. options = Object.assign({
  362. protocolVersion: protocolVersions[1],
  363. perMessageDeflate: true
  364. }, options, {
  365. createConnection: undefined,
  366. socketPath: undefined,
  367. hostname: undefined,
  368. protocol: undefined,
  369. timeout: undefined,
  370. method: undefined,
  371. auth: undefined,
  372. host: undefined,
  373. path: undefined,
  374. port: undefined
  375. });
  376. if (protocolVersions.indexOf(options.protocolVersion) === -1) {
  377. throw new RangeError(
  378. `Unsupported protocol version: ${options.protocolVersion} ` +
  379. `(supported versions: ${protocolVersions.join(', ')})`
  380. );
  381. }
  382. this._isServer = false;
  383. var parsedUrl;
  384. if (typeof address === 'object' && address.href !== undefined) {
  385. parsedUrl = address;
  386. this.url = address.href;
  387. } else {
  388. parsedUrl = url.parse(address);
  389. this.url = address;
  390. }
  391. const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
  392. if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) {
  393. throw new Error(`Invalid URL: ${this.url}`);
  394. }
  395. const isSecure = parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:';
  396. const key = crypto.randomBytes(16).toString('base64');
  397. const httpObj = isSecure ? https : http;
  398. const path = parsedUrl.search
  399. ? `${parsedUrl.pathname || '/'}${parsedUrl.search}`
  400. : parsedUrl.pathname || '/';
  401. var perMessageDeflate;
  402. options.createConnection = isSecure ? tlsConnect : netConnect;
  403. options.port = parsedUrl.port || (isSecure ? 443 : 80);
  404. options.host = parsedUrl.hostname.startsWith('[')
  405. ? parsedUrl.hostname.slice(1, -1)
  406. : parsedUrl.hostname;
  407. options.headers = Object.assign({
  408. 'Sec-WebSocket-Version': options.protocolVersion,
  409. 'Sec-WebSocket-Key': key,
  410. 'Connection': 'Upgrade',
  411. 'Upgrade': 'websocket'
  412. }, options.headers);
  413. options.path = path;
  414. if (options.perMessageDeflate) {
  415. perMessageDeflate = new PerMessageDeflate(
  416. options.perMessageDeflate !== true ? options.perMessageDeflate : {},
  417. false
  418. );
  419. options.headers['Sec-WebSocket-Extensions'] = extension.format({
  420. [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
  421. });
  422. }
  423. if (protocols) {
  424. options.headers['Sec-WebSocket-Protocol'] = protocols;
  425. }
  426. if (options.origin) {
  427. if (options.protocolVersion < 13) {
  428. options.headers['Sec-WebSocket-Origin'] = options.origin;
  429. } else {
  430. options.headers.Origin = options.origin;
  431. }
  432. }
  433. if (parsedUrl.auth) {
  434. options.auth = parsedUrl.auth;
  435. } else if (parsedUrl.username || parsedUrl.password) {
  436. options.auth = `${parsedUrl.username}:${parsedUrl.password}`;
  437. }
  438. if (isUnixSocket) {
  439. const parts = path.split(':');
  440. if (options.agent == null && process.versions.modules < 57) {
  441. //
  442. // Setting `socketPath` in conjunction with `createConnection` without an
  443. // agent throws an error on Node.js < 8. Work around the issue by using a
  444. // different property.
  445. //
  446. options._socketPath = parts[0];
  447. } else {
  448. options.socketPath = parts[0];
  449. }
  450. options.path = parts[1];
  451. }
  452. var req = this._req = httpObj.get(options);
  453. if (options.handshakeTimeout) {
  454. req.setTimeout(
  455. options.handshakeTimeout,
  456. () => abortHandshake(this, req, 'Opening handshake has timed out')
  457. );
  458. }
  459. req.on('error', (err) => {
  460. if (this._req.aborted) return;
  461. req = this._req = null;
  462. this.readyState = WebSocket.CLOSING;
  463. this.emit('error', err);
  464. this.emitClose();
  465. });
  466. req.on('response', (res) => {
  467. if (this.emit('unexpected-response', req, res)) return;
  468. abortHandshake(this, req, `Unexpected server response: ${res.statusCode}`);
  469. });
  470. req.on('upgrade', (res, socket, head) => {
  471. this.emit('upgrade', res);
  472. //
  473. // The user may have closed the connection from a listener of the `upgrade`
  474. // event.
  475. //
  476. if (this.readyState !== WebSocket.CONNECTING) return;
  477. req = this._req = null;
  478. const digest = crypto.createHash('sha1')
  479. .update(key + constants.GUID, 'binary')
  480. .digest('base64');
  481. if (res.headers['sec-websocket-accept'] !== digest) {
  482. abortHandshake(this, socket, 'Invalid Sec-WebSocket-Accept header');
  483. return;
  484. }
  485. const serverProt = res.headers['sec-websocket-protocol'];
  486. const protList = (protocols || '').split(/, */);
  487. var protError;
  488. if (!protocols && serverProt) {
  489. protError = 'Server sent a subprotocol but none was requested';
  490. } else if (protocols && !serverProt) {
  491. protError = 'Server sent no subprotocol';
  492. } else if (serverProt && protList.indexOf(serverProt) === -1) {
  493. protError = 'Server sent an invalid subprotocol';
  494. }
  495. if (protError) {
  496. abortHandshake(this, socket, protError);
  497. return;
  498. }
  499. if (serverProt) this.protocol = serverProt;
  500. if (perMessageDeflate) {
  501. try {
  502. const extensions = extension.parse(
  503. res.headers['sec-websocket-extensions']
  504. );
  505. if (extensions[PerMessageDeflate.extensionName]) {
  506. perMessageDeflate.accept(
  507. extensions[PerMessageDeflate.extensionName]
  508. );
  509. this._extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
  510. }
  511. } catch (err) {
  512. abortHandshake(this, socket, 'Invalid Sec-WebSocket-Extensions header');
  513. return;
  514. }
  515. }
  516. this.setSocket(socket, head, 0);
  517. });
  518. }
  519. /**
  520. * Create a `net.Socket` and initiate a connection.
  521. *
  522. * @param {Object} options Connection options
  523. * @return {net.Socket} The newly created socket used to start the connection
  524. * @private
  525. */
  526. function netConnect (options) {
  527. options.path = options.socketPath || options._socketPath || undefined;
  528. return net.connect(options);
  529. }
  530. /**
  531. * Create a `tls.TLSSocket` and initiate a connection.
  532. *
  533. * @param {Object} options Connection options
  534. * @return {tls.TLSSocket} The newly created socket used to start the connection
  535. * @private
  536. */
  537. function tlsConnect (options) {
  538. options.path = options.socketPath || options._socketPath || undefined;
  539. options.servername = options.servername || options.host;
  540. return tls.connect(options);
  541. }
  542. /**
  543. * Abort the handshake and emit an error.
  544. *
  545. * @param {WebSocket} websocket The WebSocket instance
  546. * @param {(http.ClientRequest|net.Socket)} stream The request to abort or the
  547. * socket to destroy
  548. * @param {String} message The error message
  549. * @private
  550. */
  551. function abortHandshake (websocket, stream, message) {
  552. websocket.readyState = WebSocket.CLOSING;
  553. const err = new Error(message);
  554. Error.captureStackTrace(err, abortHandshake);
  555. if (stream.setHeader) {
  556. stream.abort();
  557. stream.once('abort', websocket.emitClose.bind(websocket));
  558. websocket.emit('error', err);
  559. } else {
  560. stream.destroy(err);
  561. stream.once('error', websocket.emit.bind(websocket, 'error'));
  562. stream.once('close', websocket.emitClose.bind(websocket));
  563. }
  564. }
  565. /**
  566. * The listener of the `Receiver` `'conclude'` event.
  567. *
  568. * @param {Number} code The status code
  569. * @param {String} reason The reason for closing
  570. * @private
  571. */
  572. function receiverOnConclude (code, reason) {
  573. const websocket = this[kWebSocket];
  574. websocket._socket.removeListener('data', socketOnData);
  575. websocket._socket.resume();
  576. websocket._closeFrameReceived = true;
  577. websocket._closeMessage = reason;
  578. websocket._closeCode = code;
  579. if (code === 1005) websocket.close();
  580. else websocket.close(code, reason);
  581. }
  582. /**
  583. * The listener of the `Receiver` `'drain'` event.
  584. *
  585. * @private
  586. */
  587. function receiverOnDrain () {
  588. this[kWebSocket]._socket.resume();
  589. }
  590. /**
  591. * The listener of the `Receiver` `'error'` event.
  592. *
  593. * @param {(RangeError|Error)} err The emitted error
  594. * @private
  595. */
  596. function receiverOnError (err) {
  597. const websocket = this[kWebSocket];
  598. websocket._socket.removeListener('data', socketOnData);
  599. websocket.readyState = WebSocket.CLOSING;
  600. websocket._closeCode = err[constants.kStatusCode];
  601. websocket.emit('error', err);
  602. websocket._socket.destroy();
  603. }
  604. /**
  605. * The listener of the `Receiver` `'finish'` event.
  606. *
  607. * @private
  608. */
  609. function receiverOnFinish () {
  610. this[kWebSocket].emitClose();
  611. }
  612. /**
  613. * The listener of the `Receiver` `'message'` event.
  614. *
  615. * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The message
  616. * @private
  617. */
  618. function receiverOnMessage (data) {
  619. this[kWebSocket].emit('message', data);
  620. }
  621. /**
  622. * The listener of the `Receiver` `'ping'` event.
  623. *
  624. * @param {Buffer} data The data included in the ping frame
  625. * @private
  626. */
  627. function receiverOnPing (data) {
  628. const websocket = this[kWebSocket];
  629. websocket.pong(data, !websocket._isServer, constants.NOOP);
  630. websocket.emit('ping', data);
  631. }
  632. /**
  633. * The listener of the `Receiver` `'pong'` event.
  634. *
  635. * @param {Buffer} data The data included in the pong frame
  636. * @private
  637. */
  638. function receiverOnPong (data) {
  639. this[kWebSocket].emit('pong', data);
  640. }
  641. /**
  642. * The listener of the `net.Socket` `'close'` event.
  643. *
  644. * @private
  645. */
  646. function socketOnClose () {
  647. const websocket = this[kWebSocket];
  648. this.removeListener('close', socketOnClose);
  649. this.removeListener('end', socketOnEnd);
  650. websocket.readyState = WebSocket.CLOSING;
  651. //
  652. // The close frame might not have been received or the `'end'` event emitted,
  653. // for example, if the socket was destroyed due to an error. Ensure that the
  654. // `receiver` stream is closed after writing any remaining buffered data to
  655. // it. If the readable side of the socket is in flowing mode then there is no
  656. // buffered data as everything has been already written and `readable.read()`
  657. // will return `null`. If instead, the socket is paused, any possible buffered
  658. // data will be read as a single chunk and emitted synchronously in a single
  659. // `'data'` event.
  660. //
  661. websocket._socket.read();
  662. websocket._receiver.end();
  663. this.removeListener('data', socketOnData);
  664. this[kWebSocket] = undefined;
  665. clearTimeout(websocket._closeTimer);
  666. if (
  667. websocket._receiver._writableState.finished ||
  668. websocket._receiver._writableState.errorEmitted
  669. ) {
  670. websocket.emitClose();
  671. } else {
  672. websocket._receiver.on('error', receiverOnFinish);
  673. websocket._receiver.on('finish', receiverOnFinish);
  674. }
  675. }
  676. /**
  677. * The listener of the `net.Socket` `'data'` event.
  678. *
  679. * @param {Buffer} chunk A chunk of data
  680. * @private
  681. */
  682. function socketOnData (chunk) {
  683. if (!this[kWebSocket]._receiver.write(chunk)) {
  684. this.pause();
  685. }
  686. }
  687. /**
  688. * The listener of the `net.Socket` `'end'` event.
  689. *
  690. * @private
  691. */
  692. function socketOnEnd () {
  693. const websocket = this[kWebSocket];
  694. websocket.readyState = WebSocket.CLOSING;
  695. websocket._receiver.end();
  696. this.end();
  697. }
  698. /**
  699. * The listener of the `net.Socket` `'error'` event.
  700. *
  701. * @private
  702. */
  703. function socketOnError () {
  704. const websocket = this[kWebSocket];
  705. this.removeListener('error', socketOnError);
  706. this.on('error', constants.NOOP);
  707. if (websocket) {
  708. websocket.readyState = WebSocket.CLOSING;
  709. this.destroy();
  710. }
  711. }