websocket.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */
  2. 'use strict';
  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 { Readable } = require('stream');
  10. const { URL } = require('url');
  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. kForOnEventAttribute,
  19. kListener,
  20. kStatusCode,
  21. kWebSocket,
  22. NOOP
  23. } = require('./constants');
  24. const {
  25. EventTarget: { addEventListener, removeEventListener }
  26. } = require('./event-target');
  27. const { format, parse } = require('./extension');
  28. const { toBuffer } = require('./buffer-util');
  29. const closeTimeout = 30 * 1000;
  30. const kAborted = Symbol('kAborted');
  31. const protocolVersions = [8, 13];
  32. const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
  33. const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
  34. /**
  35. * Class representing a WebSocket.
  36. *
  37. * @extends EventEmitter
  38. */
  39. class WebSocket extends EventEmitter {
  40. /**
  41. * Create a new `WebSocket`.
  42. *
  43. * @param {(String|URL)} address The URL to which to connect
  44. * @param {(String|String[])} [protocols] The subprotocols
  45. * @param {Object} [options] Connection options
  46. */
  47. constructor(address, protocols, options) {
  48. super();
  49. this._binaryType = BINARY_TYPES[0];
  50. this._closeCode = 1006;
  51. this._closeFrameReceived = false;
  52. this._closeFrameSent = false;
  53. this._closeMessage = EMPTY_BUFFER;
  54. this._closeTimer = null;
  55. this._extensions = {};
  56. this._paused = false;
  57. this._protocol = '';
  58. this._readyState = WebSocket.CONNECTING;
  59. this._receiver = null;
  60. this._sender = null;
  61. this._socket = null;
  62. if (address !== null) {
  63. this._bufferedAmount = 0;
  64. this._isServer = false;
  65. this._redirects = 0;
  66. if (protocols === undefined) {
  67. protocols = [];
  68. } else if (!Array.isArray(protocols)) {
  69. if (typeof protocols === 'object' && protocols !== null) {
  70. options = protocols;
  71. protocols = [];
  72. } else {
  73. protocols = [protocols];
  74. }
  75. }
  76. initAsClient(this, address, protocols, options);
  77. } else {
  78. this._isServer = true;
  79. }
  80. }
  81. /**
  82. * This deviates from the WHATWG interface since ws doesn't support the
  83. * required default "blob" type (instead we define a custom "nodebuffer"
  84. * type).
  85. *
  86. * @type {String}
  87. */
  88. get binaryType() {
  89. return this._binaryType;
  90. }
  91. set binaryType(type) {
  92. if (!BINARY_TYPES.includes(type)) return;
  93. this._binaryType = type;
  94. //
  95. // Allow to change `binaryType` on the fly.
  96. //
  97. if (this._receiver) this._receiver._binaryType = type;
  98. }
  99. /**
  100. * @type {Number}
  101. */
  102. get bufferedAmount() {
  103. if (!this._socket) return this._bufferedAmount;
  104. return this._socket._writableState.length + this._sender._bufferedBytes;
  105. }
  106. /**
  107. * @type {String}
  108. */
  109. get extensions() {
  110. return Object.keys(this._extensions).join();
  111. }
  112. /**
  113. * @type {Boolean}
  114. */
  115. get isPaused() {
  116. return this._paused;
  117. }
  118. /**
  119. * @type {Function}
  120. */
  121. /* istanbul ignore next */
  122. get onclose() {
  123. return null;
  124. }
  125. /**
  126. * @type {Function}
  127. */
  128. /* istanbul ignore next */
  129. get onerror() {
  130. return null;
  131. }
  132. /**
  133. * @type {Function}
  134. */
  135. /* istanbul ignore next */
  136. get onopen() {
  137. return null;
  138. }
  139. /**
  140. * @type {Function}
  141. */
  142. /* istanbul ignore next */
  143. get onmessage() {
  144. return null;
  145. }
  146. /**
  147. * @type {String}
  148. */
  149. get protocol() {
  150. return this._protocol;
  151. }
  152. /**
  153. * @type {Number}
  154. */
  155. get readyState() {
  156. return this._readyState;
  157. }
  158. /**
  159. * @type {String}
  160. */
  161. get url() {
  162. return this._url;
  163. }
  164. /**
  165. * Set up the socket and the internal resources.
  166. *
  167. * @param {(net.Socket|tls.Socket)} socket The network socket between the
  168. * server and client
  169. * @param {Buffer} head The first packet of the upgraded stream
  170. * @param {Object} options Options object
  171. * @param {Function} [options.generateMask] The function used to generate the
  172. * masking key
  173. * @param {Number} [options.maxPayload=0] The maximum allowed message size
  174. * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
  175. * not to skip UTF-8 validation for text and close messages
  176. * @private
  177. */
  178. setSocket(socket, head, options) {
  179. const receiver = new Receiver({
  180. binaryType: this.binaryType,
  181. extensions: this._extensions,
  182. isServer: this._isServer,
  183. maxPayload: options.maxPayload,
  184. skipUTF8Validation: options.skipUTF8Validation
  185. });
  186. this._sender = new Sender(socket, this._extensions, options.generateMask);
  187. this._receiver = receiver;
  188. this._socket = socket;
  189. receiver[kWebSocket] = this;
  190. socket[kWebSocket] = this;
  191. receiver.on('conclude', receiverOnConclude);
  192. receiver.on('drain', receiverOnDrain);
  193. receiver.on('error', receiverOnError);
  194. receiver.on('message', receiverOnMessage);
  195. receiver.on('ping', receiverOnPing);
  196. receiver.on('pong', receiverOnPong);
  197. socket.setTimeout(0);
  198. socket.setNoDelay();
  199. if (head.length > 0) socket.unshift(head);
  200. socket.on('close', socketOnClose);
  201. socket.on('data', socketOnData);
  202. socket.on('end', socketOnEnd);
  203. socket.on('error', socketOnError);
  204. this._readyState = WebSocket.OPEN;
  205. this.emit('open');
  206. }
  207. /**
  208. * Emit the `'close'` event.
  209. *
  210. * @private
  211. */
  212. emitClose() {
  213. if (!this._socket) {
  214. this._readyState = WebSocket.CLOSED;
  215. this.emit('close', this._closeCode, this._closeMessage);
  216. return;
  217. }
  218. if (this._extensions[PerMessageDeflate.extensionName]) {
  219. this._extensions[PerMessageDeflate.extensionName].cleanup();
  220. }
  221. this._receiver.removeAllListeners();
  222. this._readyState = WebSocket.CLOSED;
  223. this.emit('close', this._closeCode, this._closeMessage);
  224. }
  225. /**
  226. * Start a closing handshake.
  227. *
  228. * +----------+ +-----------+ +----------+
  229. * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
  230. * | +----------+ +-----------+ +----------+ |
  231. * +----------+ +-----------+ |
  232. * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
  233. * +----------+ +-----------+ |
  234. * | | | +---+ |
  235. * +------------------------+-->|fin| - - - -
  236. * | +---+ | +---+
  237. * - - - - -|fin|<---------------------+
  238. * +---+
  239. *
  240. * @param {Number} [code] Status code explaining why the connection is closing
  241. * @param {(String|Buffer)} [data] The reason why the connection is
  242. * closing
  243. * @public
  244. */
  245. close(code, data) {
  246. if (this.readyState === WebSocket.CLOSED) return;
  247. if (this.readyState === WebSocket.CONNECTING) {
  248. const msg = 'WebSocket was closed before the connection was established';
  249. return abortHandshake(this, this._req, msg);
  250. }
  251. if (this.readyState === WebSocket.CLOSING) {
  252. if (
  253. this._closeFrameSent &&
  254. (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
  255. ) {
  256. this._socket.end();
  257. }
  258. return;
  259. }
  260. this._readyState = WebSocket.CLOSING;
  261. this._sender.close(code, data, !this._isServer, (err) => {
  262. //
  263. // This error is handled by the `'error'` listener on the socket. We only
  264. // want to know if the close frame has been sent here.
  265. //
  266. if (err) return;
  267. this._closeFrameSent = true;
  268. if (
  269. this._closeFrameReceived ||
  270. this._receiver._writableState.errorEmitted
  271. ) {
  272. this._socket.end();
  273. }
  274. });
  275. //
  276. // Specify a timeout for the closing handshake to complete.
  277. //
  278. this._closeTimer = setTimeout(
  279. this._socket.destroy.bind(this._socket),
  280. closeTimeout
  281. );
  282. }
  283. /**
  284. * Pause the socket.
  285. *
  286. * @public
  287. */
  288. pause() {
  289. if (
  290. this.readyState === WebSocket.CONNECTING ||
  291. this.readyState === WebSocket.CLOSED
  292. ) {
  293. return;
  294. }
  295. this._paused = true;
  296. this._socket.pause();
  297. }
  298. /**
  299. * Send a ping.
  300. *
  301. * @param {*} [data] The data to send
  302. * @param {Boolean} [mask] Indicates whether or not to mask `data`
  303. * @param {Function} [cb] Callback which is executed when the ping is sent
  304. * @public
  305. */
  306. ping(data, mask, cb) {
  307. if (this.readyState === WebSocket.CONNECTING) {
  308. throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
  309. }
  310. if (typeof data === 'function') {
  311. cb = data;
  312. data = mask = undefined;
  313. } else if (typeof mask === 'function') {
  314. cb = mask;
  315. mask = undefined;
  316. }
  317. if (typeof data === 'number') data = data.toString();
  318. if (this.readyState !== WebSocket.OPEN) {
  319. sendAfterClose(this, data, cb);
  320. return;
  321. }
  322. if (mask === undefined) mask = !this._isServer;
  323. this._sender.ping(data || EMPTY_BUFFER, mask, cb);
  324. }
  325. /**
  326. * Send a pong.
  327. *
  328. * @param {*} [data] The data to send
  329. * @param {Boolean} [mask] Indicates whether or not to mask `data`
  330. * @param {Function} [cb] Callback which is executed when the pong is sent
  331. * @public
  332. */
  333. pong(data, mask, cb) {
  334. if (this.readyState === WebSocket.CONNECTING) {
  335. throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
  336. }
  337. if (typeof data === 'function') {
  338. cb = data;
  339. data = mask = undefined;
  340. } else if (typeof mask === 'function') {
  341. cb = mask;
  342. mask = undefined;
  343. }
  344. if (typeof data === 'number') data = data.toString();
  345. if (this.readyState !== WebSocket.OPEN) {
  346. sendAfterClose(this, data, cb);
  347. return;
  348. }
  349. if (mask === undefined) mask = !this._isServer;
  350. this._sender.pong(data || EMPTY_BUFFER, mask, cb);
  351. }
  352. /**
  353. * Resume the socket.
  354. *
  355. * @public
  356. */
  357. resume() {
  358. if (
  359. this.readyState === WebSocket.CONNECTING ||
  360. this.readyState === WebSocket.CLOSED
  361. ) {
  362. return;
  363. }
  364. this._paused = false;
  365. if (!this._receiver._writableState.needDrain) this._socket.resume();
  366. }
  367. /**
  368. * Send a data message.
  369. *
  370. * @param {*} data The message to send
  371. * @param {Object} [options] Options object
  372. * @param {Boolean} [options.binary] Specifies whether `data` is binary or
  373. * text
  374. * @param {Boolean} [options.compress] Specifies whether or not to compress
  375. * `data`
  376. * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
  377. * last one
  378. * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
  379. * @param {Function} [cb] Callback which is executed when data is written out
  380. * @public
  381. */
  382. send(data, options, cb) {
  383. if (this.readyState === WebSocket.CONNECTING) {
  384. throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
  385. }
  386. if (typeof options === 'function') {
  387. cb = options;
  388. options = {};
  389. }
  390. if (typeof data === 'number') data = data.toString();
  391. if (this.readyState !== WebSocket.OPEN) {
  392. sendAfterClose(this, data, cb);
  393. return;
  394. }
  395. const opts = {
  396. binary: typeof data !== 'string',
  397. mask: !this._isServer,
  398. compress: true,
  399. fin: true,
  400. ...options
  401. };
  402. if (!this._extensions[PerMessageDeflate.extensionName]) {
  403. opts.compress = false;
  404. }
  405. this._sender.send(data || EMPTY_BUFFER, opts, cb);
  406. }
  407. /**
  408. * Forcibly close the connection.
  409. *
  410. * @public
  411. */
  412. terminate() {
  413. if (this.readyState === WebSocket.CLOSED) return;
  414. if (this.readyState === WebSocket.CONNECTING) {
  415. const msg = 'WebSocket was closed before the connection was established';
  416. return abortHandshake(this, this._req, msg);
  417. }
  418. if (this._socket) {
  419. this._readyState = WebSocket.CLOSING;
  420. this._socket.destroy();
  421. }
  422. }
  423. }
  424. /**
  425. * @constant {Number} CONNECTING
  426. * @memberof WebSocket
  427. */
  428. Object.defineProperty(WebSocket, 'CONNECTING', {
  429. enumerable: true,
  430. value: readyStates.indexOf('CONNECTING')
  431. });
  432. /**
  433. * @constant {Number} CONNECTING
  434. * @memberof WebSocket.prototype
  435. */
  436. Object.defineProperty(WebSocket.prototype, 'CONNECTING', {
  437. enumerable: true,
  438. value: readyStates.indexOf('CONNECTING')
  439. });
  440. /**
  441. * @constant {Number} OPEN
  442. * @memberof WebSocket
  443. */
  444. Object.defineProperty(WebSocket, 'OPEN', {
  445. enumerable: true,
  446. value: readyStates.indexOf('OPEN')
  447. });
  448. /**
  449. * @constant {Number} OPEN
  450. * @memberof WebSocket.prototype
  451. */
  452. Object.defineProperty(WebSocket.prototype, 'OPEN', {
  453. enumerable: true,
  454. value: readyStates.indexOf('OPEN')
  455. });
  456. /**
  457. * @constant {Number} CLOSING
  458. * @memberof WebSocket
  459. */
  460. Object.defineProperty(WebSocket, 'CLOSING', {
  461. enumerable: true,
  462. value: readyStates.indexOf('CLOSING')
  463. });
  464. /**
  465. * @constant {Number} CLOSING
  466. * @memberof WebSocket.prototype
  467. */
  468. Object.defineProperty(WebSocket.prototype, 'CLOSING', {
  469. enumerable: true,
  470. value: readyStates.indexOf('CLOSING')
  471. });
  472. /**
  473. * @constant {Number} CLOSED
  474. * @memberof WebSocket
  475. */
  476. Object.defineProperty(WebSocket, 'CLOSED', {
  477. enumerable: true,
  478. value: readyStates.indexOf('CLOSED')
  479. });
  480. /**
  481. * @constant {Number} CLOSED
  482. * @memberof WebSocket.prototype
  483. */
  484. Object.defineProperty(WebSocket.prototype, 'CLOSED', {
  485. enumerable: true,
  486. value: readyStates.indexOf('CLOSED')
  487. });
  488. [
  489. 'binaryType',
  490. 'bufferedAmount',
  491. 'extensions',
  492. 'isPaused',
  493. 'protocol',
  494. 'readyState',
  495. 'url'
  496. ].forEach((property) => {
  497. Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
  498. });
  499. //
  500. // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
  501. // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
  502. //
  503. ['open', 'error', 'close', 'message'].forEach((method) => {
  504. Object.defineProperty(WebSocket.prototype, `on${method}`, {
  505. enumerable: true,
  506. get() {
  507. for (const listener of this.listeners(method)) {
  508. if (listener[kForOnEventAttribute]) return listener[kListener];
  509. }
  510. return null;
  511. },
  512. set(handler) {
  513. for (const listener of this.listeners(method)) {
  514. if (listener[kForOnEventAttribute]) {
  515. this.removeListener(method, listener);
  516. break;
  517. }
  518. }
  519. if (typeof handler !== 'function') return;
  520. this.addEventListener(method, handler, {
  521. [kForOnEventAttribute]: true
  522. });
  523. }
  524. });
  525. });
  526. WebSocket.prototype.addEventListener = addEventListener;
  527. WebSocket.prototype.removeEventListener = removeEventListener;
  528. module.exports = WebSocket;
  529. /**
  530. * Initialize a WebSocket client.
  531. *
  532. * @param {WebSocket} websocket The client to initialize
  533. * @param {(String|URL)} address The URL to which to connect
  534. * @param {Array} protocols The subprotocols
  535. * @param {Object} [options] Connection options
  536. * @param {Boolean} [options.followRedirects=false] Whether or not to follow
  537. * redirects
  538. * @param {Function} [options.generateMask] The function used to generate the
  539. * masking key
  540. * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
  541. * handshake request
  542. * @param {Number} [options.maxPayload=104857600] The maximum allowed message
  543. * size
  544. * @param {Number} [options.maxRedirects=10] The maximum number of redirects
  545. * allowed
  546. * @param {String} [options.origin] Value of the `Origin` or
  547. * `Sec-WebSocket-Origin` header
  548. * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
  549. * permessage-deflate
  550. * @param {Number} [options.protocolVersion=13] Value of the
  551. * `Sec-WebSocket-Version` header
  552. * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
  553. * not to skip UTF-8 validation for text and close messages
  554. * @private
  555. */
  556. function initAsClient(websocket, address, protocols, options) {
  557. const opts = {
  558. protocolVersion: protocolVersions[1],
  559. maxPayload: 100 * 1024 * 1024,
  560. skipUTF8Validation: false,
  561. perMessageDeflate: true,
  562. followRedirects: false,
  563. maxRedirects: 10,
  564. ...options,
  565. createConnection: undefined,
  566. socketPath: undefined,
  567. hostname: undefined,
  568. protocol: undefined,
  569. timeout: undefined,
  570. method: 'GET',
  571. host: undefined,
  572. path: undefined,
  573. port: undefined
  574. };
  575. if (!protocolVersions.includes(opts.protocolVersion)) {
  576. throw new RangeError(
  577. `Unsupported protocol version: ${opts.protocolVersion} ` +
  578. `(supported versions: ${protocolVersions.join(', ')})`
  579. );
  580. }
  581. let parsedUrl;
  582. if (address instanceof URL) {
  583. parsedUrl = address;
  584. websocket._url = address.href;
  585. } else {
  586. try {
  587. parsedUrl = new URL(address);
  588. } catch (e) {
  589. throw new SyntaxError(`Invalid URL: ${address}`);
  590. }
  591. websocket._url = address;
  592. }
  593. const isSecure = parsedUrl.protocol === 'wss:';
  594. const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
  595. let invalidUrlMessage;
  596. if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
  597. invalidUrlMessage =
  598. 'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"';
  599. } else if (isIpcUrl && !parsedUrl.pathname) {
  600. invalidUrlMessage = "The URL's pathname is empty";
  601. } else if (parsedUrl.hash) {
  602. invalidUrlMessage = 'The URL contains a fragment identifier';
  603. }
  604. if (invalidUrlMessage) {
  605. const err = new SyntaxError(invalidUrlMessage);
  606. if (websocket._redirects === 0) {
  607. throw err;
  608. } else {
  609. emitErrorAndClose(websocket, err);
  610. return;
  611. }
  612. }
  613. const defaultPort = isSecure ? 443 : 80;
  614. const key = randomBytes(16).toString('base64');
  615. const request = isSecure ? https.request : http.request;
  616. const protocolSet = new Set();
  617. let perMessageDeflate;
  618. opts.createConnection = isSecure ? tlsConnect : netConnect;
  619. opts.defaultPort = opts.defaultPort || defaultPort;
  620. opts.port = parsedUrl.port || defaultPort;
  621. opts.host = parsedUrl.hostname.startsWith('[')
  622. ? parsedUrl.hostname.slice(1, -1)
  623. : parsedUrl.hostname;
  624. opts.headers = {
  625. ...opts.headers,
  626. 'Sec-WebSocket-Version': opts.protocolVersion,
  627. 'Sec-WebSocket-Key': key,
  628. Connection: 'Upgrade',
  629. Upgrade: 'websocket'
  630. };
  631. opts.path = parsedUrl.pathname + parsedUrl.search;
  632. opts.timeout = opts.handshakeTimeout;
  633. if (opts.perMessageDeflate) {
  634. perMessageDeflate = new PerMessageDeflate(
  635. opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
  636. false,
  637. opts.maxPayload
  638. );
  639. opts.headers['Sec-WebSocket-Extensions'] = format({
  640. [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
  641. });
  642. }
  643. if (protocols.length) {
  644. for (const protocol of protocols) {
  645. if (
  646. typeof protocol !== 'string' ||
  647. !subprotocolRegex.test(protocol) ||
  648. protocolSet.has(protocol)
  649. ) {
  650. throw new SyntaxError(
  651. 'An invalid or duplicated subprotocol was specified'
  652. );
  653. }
  654. protocolSet.add(protocol);
  655. }
  656. opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');
  657. }
  658. if (opts.origin) {
  659. if (opts.protocolVersion < 13) {
  660. opts.headers['Sec-WebSocket-Origin'] = opts.origin;
  661. } else {
  662. opts.headers.Origin = opts.origin;
  663. }
  664. }
  665. if (parsedUrl.username || parsedUrl.password) {
  666. opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
  667. }
  668. if (isIpcUrl) {
  669. const parts = opts.path.split(':');
  670. opts.socketPath = parts[0];
  671. opts.path = parts[1];
  672. }
  673. let req;
  674. if (opts.followRedirects) {
  675. if (websocket._redirects === 0) {
  676. websocket._originalIpc = isIpcUrl;
  677. websocket._originalSecure = isSecure;
  678. websocket._originalHostOrSocketPath = isIpcUrl
  679. ? opts.socketPath
  680. : parsedUrl.host;
  681. const headers = options && options.headers;
  682. //
  683. // Shallow copy the user provided options so that headers can be changed
  684. // without mutating the original object.
  685. //
  686. options = { ...options, headers: {} };
  687. if (headers) {
  688. for (const [key, value] of Object.entries(headers)) {
  689. options.headers[key.toLowerCase()] = value;
  690. }
  691. }
  692. } else if (websocket.listenerCount('redirect') === 0) {
  693. const isSameHost = isIpcUrl
  694. ? websocket._originalIpc
  695. ? opts.socketPath === websocket._originalHostOrSocketPath
  696. : false
  697. : websocket._originalIpc
  698. ? false
  699. : parsedUrl.host === websocket._originalHostOrSocketPath;
  700. if (!isSameHost || (websocket._originalSecure && !isSecure)) {
  701. //
  702. // Match curl 7.77.0 behavior and drop the following headers. These
  703. // headers are also dropped when following a redirect to a subdomain.
  704. //
  705. delete opts.headers.authorization;
  706. delete opts.headers.cookie;
  707. if (!isSameHost) delete opts.headers.host;
  708. opts.auth = undefined;
  709. }
  710. }
  711. //
  712. // Match curl 7.77.0 behavior and make the first `Authorization` header win.
  713. // If the `Authorization` header is set, then there is nothing to do as it
  714. // will take precedence.
  715. //
  716. if (opts.auth && !options.headers.authorization) {
  717. options.headers.authorization =
  718. 'Basic ' + Buffer.from(opts.auth).toString('base64');
  719. }
  720. req = websocket._req = request(opts);
  721. if (websocket._redirects) {
  722. //
  723. // Unlike what is done for the `'upgrade'` event, no early exit is
  724. // triggered here if the user calls `websocket.close()` or
  725. // `websocket.terminate()` from a listener of the `'redirect'` event. This
  726. // is because the user can also call `request.destroy()` with an error
  727. // before calling `websocket.close()` or `websocket.terminate()` and this
  728. // would result in an error being emitted on the `request` object with no
  729. // `'error'` event listeners attached.
  730. //
  731. websocket.emit('redirect', websocket.url, req);
  732. }
  733. } else {
  734. req = websocket._req = request(opts);
  735. }
  736. if (opts.timeout) {
  737. req.on('timeout', () => {
  738. abortHandshake(websocket, req, 'Opening handshake has timed out');
  739. });
  740. }
  741. req.on('error', (err) => {
  742. if (req === null || req[kAborted]) return;
  743. req = websocket._req = null;
  744. emitErrorAndClose(websocket, err);
  745. });
  746. req.on('response', (res) => {
  747. const location = res.headers.location;
  748. const statusCode = res.statusCode;
  749. if (
  750. location &&
  751. opts.followRedirects &&
  752. statusCode >= 300 &&
  753. statusCode < 400
  754. ) {
  755. if (++websocket._redirects > opts.maxRedirects) {
  756. abortHandshake(websocket, req, 'Maximum redirects exceeded');
  757. return;
  758. }
  759. req.abort();
  760. let addr;
  761. try {
  762. addr = new URL(location, address);
  763. } catch (e) {
  764. const err = new SyntaxError(`Invalid URL: ${location}`);
  765. emitErrorAndClose(websocket, err);
  766. return;
  767. }
  768. initAsClient(websocket, addr, protocols, options);
  769. } else if (!websocket.emit('unexpected-response', req, res)) {
  770. abortHandshake(
  771. websocket,
  772. req,
  773. `Unexpected server response: ${res.statusCode}`
  774. );
  775. }
  776. });
  777. req.on('upgrade', (res, socket, head) => {
  778. websocket.emit('upgrade', res);
  779. //
  780. // The user may have closed the connection from a listener of the
  781. // `'upgrade'` event.
  782. //
  783. if (websocket.readyState !== WebSocket.CONNECTING) return;
  784. req = websocket._req = null;
  785. if (res.headers.upgrade.toLowerCase() !== 'websocket') {
  786. abortHandshake(websocket, socket, 'Invalid Upgrade header');
  787. return;
  788. }
  789. const digest = createHash('sha1')
  790. .update(key + GUID)
  791. .digest('base64');
  792. if (res.headers['sec-websocket-accept'] !== digest) {
  793. abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
  794. return;
  795. }
  796. const serverProt = res.headers['sec-websocket-protocol'];
  797. let protError;
  798. if (serverProt !== undefined) {
  799. if (!protocolSet.size) {
  800. protError = 'Server sent a subprotocol but none was requested';
  801. } else if (!protocolSet.has(serverProt)) {
  802. protError = 'Server sent an invalid subprotocol';
  803. }
  804. } else if (protocolSet.size) {
  805. protError = 'Server sent no subprotocol';
  806. }
  807. if (protError) {
  808. abortHandshake(websocket, socket, protError);
  809. return;
  810. }
  811. if (serverProt) websocket._protocol = serverProt;
  812. const secWebSocketExtensions = res.headers['sec-websocket-extensions'];
  813. if (secWebSocketExtensions !== undefined) {
  814. if (!perMessageDeflate) {
  815. const message =
  816. 'Server sent a Sec-WebSocket-Extensions header but no extension ' +
  817. 'was requested';
  818. abortHandshake(websocket, socket, message);
  819. return;
  820. }
  821. let extensions;
  822. try {
  823. extensions = parse(secWebSocketExtensions);
  824. } catch (err) {
  825. const message = 'Invalid Sec-WebSocket-Extensions header';
  826. abortHandshake(websocket, socket, message);
  827. return;
  828. }
  829. const extensionNames = Object.keys(extensions);
  830. if (
  831. extensionNames.length !== 1 ||
  832. extensionNames[0] !== PerMessageDeflate.extensionName
  833. ) {
  834. const message = 'Server indicated an extension that was not requested';
  835. abortHandshake(websocket, socket, message);
  836. return;
  837. }
  838. try {
  839. perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
  840. } catch (err) {
  841. const message = 'Invalid Sec-WebSocket-Extensions header';
  842. abortHandshake(websocket, socket, message);
  843. return;
  844. }
  845. websocket._extensions[PerMessageDeflate.extensionName] =
  846. perMessageDeflate;
  847. }
  848. websocket.setSocket(socket, head, {
  849. generateMask: opts.generateMask,
  850. maxPayload: opts.maxPayload,
  851. skipUTF8Validation: opts.skipUTF8Validation
  852. });
  853. });
  854. req.end();
  855. }
  856. /**
  857. * Emit the `'error'` and `'close'` events.
  858. *
  859. * @param {WebSocket} websocket The WebSocket instance
  860. * @param {Error} The error to emit
  861. * @private
  862. */
  863. function emitErrorAndClose(websocket, err) {
  864. websocket._readyState = WebSocket.CLOSING;
  865. websocket.emit('error', err);
  866. websocket.emitClose();
  867. }
  868. /**
  869. * Create a `net.Socket` and initiate a connection.
  870. *
  871. * @param {Object} options Connection options
  872. * @return {net.Socket} The newly created socket used to start the connection
  873. * @private
  874. */
  875. function netConnect(options) {
  876. options.path = options.socketPath;
  877. return net.connect(options);
  878. }
  879. /**
  880. * Create a `tls.TLSSocket` and initiate a connection.
  881. *
  882. * @param {Object} options Connection options
  883. * @return {tls.TLSSocket} The newly created socket used to start the connection
  884. * @private
  885. */
  886. function tlsConnect(options) {
  887. options.path = undefined;
  888. if (!options.servername && options.servername !== '') {
  889. options.servername = net.isIP(options.host) ? '' : options.host;
  890. }
  891. return tls.connect(options);
  892. }
  893. /**
  894. * Abort the handshake and emit an error.
  895. *
  896. * @param {WebSocket} websocket The WebSocket instance
  897. * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
  898. * abort or the socket to destroy
  899. * @param {String} message The error message
  900. * @private
  901. */
  902. function abortHandshake(websocket, stream, message) {
  903. websocket._readyState = WebSocket.CLOSING;
  904. const err = new Error(message);
  905. Error.captureStackTrace(err, abortHandshake);
  906. if (stream.setHeader) {
  907. stream[kAborted] = true;
  908. stream.abort();
  909. if (stream.socket && !stream.socket.destroyed) {
  910. //
  911. // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if
  912. // called after the request completed. See
  913. // https://github.com/websockets/ws/issues/1869.
  914. //
  915. stream.socket.destroy();
  916. }
  917. process.nextTick(emitErrorAndClose, websocket, err);
  918. } else {
  919. stream.destroy(err);
  920. stream.once('error', websocket.emit.bind(websocket, 'error'));
  921. stream.once('close', websocket.emitClose.bind(websocket));
  922. }
  923. }
  924. /**
  925. * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
  926. * when the `readyState` attribute is `CLOSING` or `CLOSED`.
  927. *
  928. * @param {WebSocket} websocket The WebSocket instance
  929. * @param {*} [data] The data to send
  930. * @param {Function} [cb] Callback
  931. * @private
  932. */
  933. function sendAfterClose(websocket, data, cb) {
  934. if (data) {
  935. const length = toBuffer(data).length;
  936. //
  937. // The `_bufferedAmount` property is used only when the peer is a client and
  938. // the opening handshake fails. Under these circumstances, in fact, the
  939. // `setSocket()` method is not called, so the `_socket` and `_sender`
  940. // properties are set to `null`.
  941. //
  942. if (websocket._socket) websocket._sender._bufferedBytes += length;
  943. else websocket._bufferedAmount += length;
  944. }
  945. if (cb) {
  946. const err = new Error(
  947. `WebSocket is not open: readyState ${websocket.readyState} ` +
  948. `(${readyStates[websocket.readyState]})`
  949. );
  950. cb(err);
  951. }
  952. }
  953. /**
  954. * The listener of the `Receiver` `'conclude'` event.
  955. *
  956. * @param {Number} code The status code
  957. * @param {Buffer} reason The reason for closing
  958. * @private
  959. */
  960. function receiverOnConclude(code, reason) {
  961. const websocket = this[kWebSocket];
  962. websocket._closeFrameReceived = true;
  963. websocket._closeMessage = reason;
  964. websocket._closeCode = code;
  965. if (websocket._socket[kWebSocket] === undefined) return;
  966. websocket._socket.removeListener('data', socketOnData);
  967. process.nextTick(resume, websocket._socket);
  968. if (code === 1005) websocket.close();
  969. else websocket.close(code, reason);
  970. }
  971. /**
  972. * The listener of the `Receiver` `'drain'` event.
  973. *
  974. * @private
  975. */
  976. function receiverOnDrain() {
  977. const websocket = this[kWebSocket];
  978. if (!websocket.isPaused) websocket._socket.resume();
  979. }
  980. /**
  981. * The listener of the `Receiver` `'error'` event.
  982. *
  983. * @param {(RangeError|Error)} err The emitted error
  984. * @private
  985. */
  986. function receiverOnError(err) {
  987. const websocket = this[kWebSocket];
  988. if (websocket._socket[kWebSocket] !== undefined) {
  989. websocket._socket.removeListener('data', socketOnData);
  990. //
  991. // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
  992. // https://github.com/websockets/ws/issues/1940.
  993. //
  994. process.nextTick(resume, websocket._socket);
  995. websocket.close(err[kStatusCode]);
  996. }
  997. websocket.emit('error', err);
  998. }
  999. /**
  1000. * The listener of the `Receiver` `'finish'` event.
  1001. *
  1002. * @private
  1003. */
  1004. function receiverOnFinish() {
  1005. this[kWebSocket].emitClose();
  1006. }
  1007. /**
  1008. * The listener of the `Receiver` `'message'` event.
  1009. *
  1010. * @param {Buffer|ArrayBuffer|Buffer[])} data The message
  1011. * @param {Boolean} isBinary Specifies whether the message is binary or not
  1012. * @private
  1013. */
  1014. function receiverOnMessage(data, isBinary) {
  1015. this[kWebSocket].emit('message', data, isBinary);
  1016. }
  1017. /**
  1018. * The listener of the `Receiver` `'ping'` event.
  1019. *
  1020. * @param {Buffer} data The data included in the ping frame
  1021. * @private
  1022. */
  1023. function receiverOnPing(data) {
  1024. const websocket = this[kWebSocket];
  1025. websocket.pong(data, !websocket._isServer, NOOP);
  1026. websocket.emit('ping', data);
  1027. }
  1028. /**
  1029. * The listener of the `Receiver` `'pong'` event.
  1030. *
  1031. * @param {Buffer} data The data included in the pong frame
  1032. * @private
  1033. */
  1034. function receiverOnPong(data) {
  1035. this[kWebSocket].emit('pong', data);
  1036. }
  1037. /**
  1038. * Resume a readable stream
  1039. *
  1040. * @param {Readable} stream The readable stream
  1041. * @private
  1042. */
  1043. function resume(stream) {
  1044. stream.resume();
  1045. }
  1046. /**
  1047. * The listener of the `net.Socket` `'close'` event.
  1048. *
  1049. * @private
  1050. */
  1051. function socketOnClose() {
  1052. const websocket = this[kWebSocket];
  1053. this.removeListener('close', socketOnClose);
  1054. this.removeListener('data', socketOnData);
  1055. this.removeListener('end', socketOnEnd);
  1056. websocket._readyState = WebSocket.CLOSING;
  1057. let chunk;
  1058. //
  1059. // The close frame might not have been received or the `'end'` event emitted,
  1060. // for example, if the socket was destroyed due to an error. Ensure that the
  1061. // `receiver` stream is closed after writing any remaining buffered data to
  1062. // it. If the readable side of the socket is in flowing mode then there is no
  1063. // buffered data as everything has been already written and `readable.read()`
  1064. // will return `null`. If instead, the socket is paused, any possible buffered
  1065. // data will be read as a single chunk.
  1066. //
  1067. if (
  1068. !this._readableState.endEmitted &&
  1069. !websocket._closeFrameReceived &&
  1070. !websocket._receiver._writableState.errorEmitted &&
  1071. (chunk = websocket._socket.read()) !== null
  1072. ) {
  1073. websocket._receiver.write(chunk);
  1074. }
  1075. websocket._receiver.end();
  1076. this[kWebSocket] = undefined;
  1077. clearTimeout(websocket._closeTimer);
  1078. if (
  1079. websocket._receiver._writableState.finished ||
  1080. websocket._receiver._writableState.errorEmitted
  1081. ) {
  1082. websocket.emitClose();
  1083. } else {
  1084. websocket._receiver.on('error', receiverOnFinish);
  1085. websocket._receiver.on('finish', receiverOnFinish);
  1086. }
  1087. }
  1088. /**
  1089. * The listener of the `net.Socket` `'data'` event.
  1090. *
  1091. * @param {Buffer} chunk A chunk of data
  1092. * @private
  1093. */
  1094. function socketOnData(chunk) {
  1095. if (!this[kWebSocket]._receiver.write(chunk)) {
  1096. this.pause();
  1097. }
  1098. }
  1099. /**
  1100. * The listener of the `net.Socket` `'end'` event.
  1101. *
  1102. * @private
  1103. */
  1104. function socketOnEnd() {
  1105. const websocket = this[kWebSocket];
  1106. websocket._readyState = WebSocket.CLOSING;
  1107. websocket._receiver.end();
  1108. this.end();
  1109. }
  1110. /**
  1111. * The listener of the `net.Socket` `'error'` event.
  1112. *
  1113. * @private
  1114. */
  1115. function socketOnError() {
  1116. const websocket = this[kWebSocket];
  1117. this.removeListener('error', socketOnError);
  1118. this.on('error', NOOP);
  1119. if (websocket) {
  1120. websocket._readyState = WebSocket.CLOSING;
  1121. this.destroy();
  1122. }
  1123. }