diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-05-12 15:59:20 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-05-25 06:57:22 +0000 |
commit | f7eaed5286974984ba5f9e3189d8f49d03e99f81 (patch) | |
tree | caed19b2af2024f35449fb0b781d0a25e09d4f8f /chromium/third_party/devtools-frontend/src/node_modules/ws | |
parent | 9729c4479fe23554eae6e6dd1f30ff488f470c84 (diff) | |
download | qtwebengine-chromium-f7eaed5286974984ba5f9e3189d8f49d03e99f81.tar.gz |
BASELINE: Update Chromium to 100.0.4896.167
Change-Id: I98cbeb5d7543d966ffe04d8cefded0c493a11333
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/devtools-frontend/src/node_modules/ws')
17 files changed, 819 insertions, 437 deletions
diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/LICENSE b/chromium/third_party/devtools-frontend/src/node_modules/ws/LICENSE index a145cd1dff0..65ff176bf67 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/LICENSE +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/LICENSE @@ -1,5 +1,3 @@ -The MIT License (MIT) - Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/README.md b/chromium/third_party/devtools-frontend/src/node_modules/ws/README.md index 1cb19d65040..82ca8db4981 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/README.md +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/README.md @@ -1,8 +1,7 @@ # ws: a Node.js WebSocket library [![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws) -[![Build](https://img.shields.io/github/workflow/status/websockets/ws/CI/master?label=build&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster) -[![Windows x86 Build](https://img.shields.io/appveyor/ci/lpinca/ws/master.svg?logo=appveyor)](https://ci.appveyor.com/project/lpinca/ws) +[![CI](https://img.shields.io/github/workflow/status/websockets/ws/CI/master?label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster) [![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws) ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and @@ -98,9 +97,9 @@ into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs]. See [the docs][ws-server-options] for more options. ```js -const WebSocket = require('ws'); +import WebSocket, { WebSocketServer } from 'ws'; -const wss = new WebSocket.Server({ +const wss = new WebSocketServer({ port: 8080, perMessageDeflate: { zlibDeflateOptions: { @@ -119,7 +118,7 @@ const wss = new WebSocket.Server({ // Below options specified as default values. concurrencyLimit: 10, // Limits zlib concurrency for perf. threshold: 1024 // Size (in bytes) below which messages - // should not be compressed. + // should not be compressed if context takeover is disabled. } }); ``` @@ -129,7 +128,7 @@ server. To always disable the extension on the client set the `perMessageDeflate` option to `false`. ```js -const WebSocket = require('ws'); +import WebSocket from 'ws'; const ws = new WebSocket('ws://www.host.com/path', { perMessageDeflate: false @@ -141,7 +140,7 @@ const ws = new WebSocket('ws://www.host.com/path', { ### Sending and receiving text data ```js -const WebSocket = require('ws'); +import WebSocket from 'ws'; const ws = new WebSocket('ws://www.host.com/path'); @@ -149,15 +148,15 @@ ws.on('open', function open() { ws.send('something'); }); -ws.on('message', function incoming(data) { - console.log(data); +ws.on('message', function message(data) { + console.log('received: %s', data); }); ``` ### Sending binary data ```js -const WebSocket = require('ws'); +import WebSocket from 'ws'; const ws = new WebSocket('ws://www.host.com/path'); @@ -175,13 +174,13 @@ ws.on('open', function open() { ### Simple server ```js -const WebSocket = require('ws'); +import { WebSocketServer } from 'ws'; -const wss = new WebSocket.Server({ port: 8080 }); +const wss = new WebSocketServer({ port: 8080 }); wss.on('connection', function connection(ws) { - ws.on('message', function incoming(message) { - console.log('received: %s', message); + ws.on('message', function message(data) { + console.log('received: %s', data); }); ws.send('something'); @@ -191,19 +190,19 @@ wss.on('connection', function connection(ws) { ### External HTTP/S server ```js -const fs = require('fs'); -const https = require('https'); -const WebSocket = require('ws'); +import { createServer } from 'https'; +import { readFileSync } from 'fs'; +import { WebSocketServer } from 'ws'; -const server = https.createServer({ - cert: fs.readFileSync('/path/to/cert.pem'), - key: fs.readFileSync('/path/to/key.pem') +const server = createServer({ + cert: readFileSync('/path/to/cert.pem'), + key: readFileSync('/path/to/key.pem') }); -const wss = new WebSocket.Server({ server }); +const wss = new WebSocketServer({ server }); wss.on('connection', function connection(ws) { - ws.on('message', function incoming(message) { - console.log('received: %s', message); + ws.on('message', function message(data) { + console.log('received: %s', data); }); ws.send('something'); @@ -215,13 +214,13 @@ server.listen(8080); ### Multiple servers sharing a single HTTP/S server ```js -const http = require('http'); -const WebSocket = require('ws'); -const url = require('url'); +import { createServer } from 'http'; +import { parse } from 'url'; +import { WebSocketServer } from 'ws'; -const server = http.createServer(); -const wss1 = new WebSocket.Server({ noServer: true }); -const wss2 = new WebSocket.Server({ noServer: true }); +const server = createServer(); +const wss1 = new WebSocketServer({ noServer: true }); +const wss2 = new WebSocketServer({ noServer: true }); wss1.on('connection', function connection(ws) { // ... @@ -232,7 +231,7 @@ wss2.on('connection', function connection(ws) { }); server.on('upgrade', function upgrade(request, socket, head) { - const pathname = url.parse(request.url).pathname; + const { pathname } = parse(request.url); if (pathname === '/foo') { wss1.handleUpgrade(request, socket, head, function done(ws) { @@ -253,21 +252,21 @@ server.listen(8080); ### Client authentication ```js -const http = require('http'); -const WebSocket = require('ws'); +import WebSocket from 'ws'; +import { createServer } from 'http'; -const server = http.createServer(); -const wss = new WebSocket.Server({ noServer: true }); +const server = createServer(); +const wss = new WebSocketServer({ noServer: true }); wss.on('connection', function connection(ws, request, client) { - ws.on('message', function message(msg) { - console.log(`Received message ${msg} from user ${client}`); + ws.on('message', function message(data) { + console.log(`Received message ${data} from user ${client}`); }); }); server.on('upgrade', function upgrade(request, socket, head) { // This function is not defined on purpose. Implement it with your own logic. - authenticate(request, (err, client) => { + authenticate(request, function next(err, client) { if (err || !client) { socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); socket.destroy(); @@ -291,15 +290,15 @@ A client WebSocket broadcasting to all connected WebSocket clients, including itself. ```js -const WebSocket = require('ws'); +import WebSocket, { WebSocketServer } from 'ws'; -const wss = new WebSocket.Server({ port: 8080 }); +const wss = new WebSocketServer({ port: 8080 }); wss.on('connection', function connection(ws) { - ws.on('message', function incoming(data) { + ws.on('message', function message(data, isBinary) { wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { - client.send(data); + client.send(data, { binary: isBinary }); } }); }); @@ -310,15 +309,15 @@ A client WebSocket broadcasting to every other connected WebSocket clients, excluding itself. ```js -const WebSocket = require('ws'); +import WebSocket, { WebSocketServer } from 'ws'; -const wss = new WebSocket.Server({ port: 8080 }); +const wss = new WebSocketServer({ port: 8080 }); wss.on('connection', function connection(ws) { - ws.on('message', function incoming(data) { + ws.on('message', function message(data, isBinary) { wss.clients.forEach(function each(client) { if (client !== ws && client.readyState === WebSocket.OPEN) { - client.send(data); + client.send(data, { binary: isBinary }); } }); }); @@ -328,7 +327,7 @@ wss.on('connection', function connection(ws) { ### echo.websocket.org demo ```js -const WebSocket = require('ws'); +import WebSocket from 'ws'; const ws = new WebSocket('wss://echo.websocket.org/', { origin: 'https://websocket.org' @@ -343,7 +342,7 @@ ws.on('close', function close() { console.log('disconnected'); }); -ws.on('message', function incoming(data) { +ws.on('message', function message(data) { console.log(`Roundtrip time: ${Date.now() - data} ms`); setTimeout(function timeout() { @@ -355,13 +354,13 @@ ws.on('message', function incoming(data) { ### Use the Node.js streams API ```js -const WebSocket = require('ws'); +import WebSocket, { createWebSocketStream } from 'ws'; const ws = new WebSocket('wss://echo.websocket.org/', { origin: 'https://websocket.org' }); -const duplex = WebSocket.createWebSocketStream(ws, { encoding: 'utf8' }); +const duplex = createWebSocketStream(ws, { encoding: 'utf8' }); duplex.pipe(process.stdout); process.stdin.pipe(duplex); @@ -381,9 +380,9 @@ Otherwise, see the test cases. The remote IP address can be obtained from the raw socket. ```js -const WebSocket = require('ws'); +import { WebSocketServer } from 'ws'; -const wss = new WebSocket.Server({ port: 8080 }); +const wss = new WebSocketServer({ port: 8080 }); wss.on('connection', function connection(ws, req) { const ip = req.socket.remoteAddress; @@ -409,15 +408,13 @@ In these cases ping messages can be used as a means to verify that the remote endpoint is still responsive. ```js -const WebSocket = require('ws'); - -function noop() {} +import { WebSocketServer } from 'ws'; function heartbeat() { this.isAlive = true; } -const wss = new WebSocket.Server({ port: 8080 }); +const wss = new WebSocketServer({ port: 8080 }); wss.on('connection', function connection(ws) { ws.isAlive = true; @@ -429,7 +426,7 @@ const interval = setInterval(function ping() { if (ws.isAlive === false) return ws.terminate(); ws.isAlive = false; - ws.ping(noop); + ws.ping(); }); }, 30000); @@ -446,7 +443,7 @@ without knowing it. You might want to add a ping listener on your clients to prevent that. A simple implementation would be: ```js -const WebSocket = require('ws'); +import WebSocket from 'ws'; function heartbeat() { clearTimeout(this.pingTimeout); diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/index.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/index.js index 722c78676ef..41edb3b81bc 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/index.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/index.js @@ -7,4 +7,7 @@ WebSocket.Server = require('./lib/websocket-server'); WebSocket.Receiver = require('./lib/receiver'); WebSocket.Sender = require('./lib/sender'); +WebSocket.WebSocket = WebSocket; +WebSocket.WebSocketServer = WebSocket.Server; + module.exports = WebSocket; diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/buffer-util.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/buffer-util.js index 6fd84c31174..1ba1d1beb32 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/buffer-util.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/buffer-util.js @@ -52,9 +52,7 @@ function _mask(source, mask, output, offset, length) { * @public */ function _unmask(buffer, mask) { - // Required until https://github.com/nodejs/node/issues/9006 is resolved. - const length = buffer.length; - for (let i = 0; i < length; i++) { + for (let i = 0; i < buffer.length; i++) { buffer[i] ^= mask[i & 3]; } } @@ -103,19 +101,18 @@ function toBuffer(data) { try { const bufferUtil = require('bufferutil'); - const bu = bufferUtil.BufferUtil || bufferUtil; module.exports = { concat, mask(source, mask, output, offset, length) { if (length < 48) _mask(source, mask, output, offset, length); - else bu.mask(source, mask, output, offset, length); + else bufferUtil.mask(source, mask, output, offset, length); }, toArrayBuffer, toBuffer, unmask(buffer, mask) { if (buffer.length < 32) _unmask(buffer, mask); - else bu.unmask(buffer, mask); + else bufferUtil.unmask(buffer, mask); } }; } catch (e) /* istanbul ignore next */ { diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/constants.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/constants.js index 4082981f89d..d691b30a17f 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/constants.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/constants.js @@ -2,9 +2,11 @@ module.exports = { BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'], + EMPTY_BUFFER: Buffer.alloc(0), GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', + kForOnEventAttribute: Symbol('kIsForOnEventAttribute'), + kListener: Symbol('kListener'), kStatusCode: Symbol('status-code'), kWebSocket: Symbol('websocket'), - EMPTY_BUFFER: Buffer.alloc(0), NOOP: () => {} }; diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/event-target.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/event-target.js index a6fbe72b7b1..d5abd83a0f6 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/event-target.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/event-target.js @@ -1,111 +1,172 @@ 'use strict'; +const { kForOnEventAttribute, kListener } = require('./constants'); + +const kCode = Symbol('kCode'); +const kData = Symbol('kData'); +const kError = Symbol('kError'); +const kMessage = Symbol('kMessage'); +const kReason = Symbol('kReason'); +const kTarget = Symbol('kTarget'); +const kType = Symbol('kType'); +const kWasClean = Symbol('kWasClean'); + /** * Class representing an event. - * - * @private */ class Event { /** * Create a new `Event`. * * @param {String} type The name of the event - * @param {Object} target A reference to the target to which the event was - * dispatched + * @throws {TypeError} If the `type` argument is not specified */ - constructor(type, target) { - this.target = target; - this.type = type; + constructor(type) { + this[kTarget] = null; + this[kType] = type; } -} -/** - * Class representing a message event. - * - * @extends Event - * @private - */ -class MessageEvent extends Event { /** - * Create a new `MessageEvent`. - * - * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data - * @param {WebSocket} target A reference to the target to which the event was - * dispatched + * @type {*} */ - constructor(data, target) { - super('message', target); + get target() { + return this[kTarget]; + } - this.data = data; + /** + * @type {String} + */ + get type() { + return this[kType]; } } +Object.defineProperty(Event.prototype, 'target', { enumerable: true }); +Object.defineProperty(Event.prototype, 'type', { enumerable: true }); + /** * Class representing a close event. * * @extends Event - * @private */ class CloseEvent extends Event { /** * Create a new `CloseEvent`. * - * @param {Number} code The status code explaining why the connection is being - * closed - * @param {String} reason A human-readable string explaining why the - * connection is closing - * @param {WebSocket} target A reference to the target to which the event was - * dispatched + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {Number} [options.code=0] The status code explaining why the + * connection was closed + * @param {String} [options.reason=''] A human-readable string explaining why + * the connection was closed + * @param {Boolean} [options.wasClean=false] Indicates whether or not the + * connection was cleanly closed + */ + constructor(type, options = {}) { + super(type); + + this[kCode] = options.code === undefined ? 0 : options.code; + this[kReason] = options.reason === undefined ? '' : options.reason; + this[kWasClean] = options.wasClean === undefined ? false : options.wasClean; + } + + /** + * @type {Number} */ - constructor(code, reason, target) { - super('close', target); + get code() { + return this[kCode]; + } + + /** + * @type {String} + */ + get reason() { + return this[kReason]; + } - this.wasClean = target._closeFrameReceived && target._closeFrameSent; - this.reason = reason; - this.code = code; + /** + * @type {Boolean} + */ + get wasClean() { + return this[kWasClean]; } } +Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true }); + /** - * Class representing an open event. + * Class representing an error event. * * @extends Event - * @private */ -class OpenEvent extends Event { +class ErrorEvent extends Event { /** - * Create a new `OpenEvent`. + * Create a new `ErrorEvent`. * - * @param {WebSocket} target A reference to the target to which the event was - * dispatched + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.error=null] The error that generated this event + * @param {String} [options.message=''] The error message */ - constructor(target) { - super('open', target); + constructor(type, options = {}) { + super(type); + + this[kError] = options.error === undefined ? null : options.error; + this[kMessage] = options.message === undefined ? '' : options.message; + } + + /** + * @type {*} + */ + get error() { + return this[kError]; + } + + /** + * @type {String} + */ + get message() { + return this[kMessage]; } } +Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true }); +Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true }); + /** - * Class representing an error event. + * Class representing a message event. * * @extends Event - * @private */ -class ErrorEvent extends Event { +class MessageEvent extends Event { /** - * Create a new `ErrorEvent`. + * Create a new `MessageEvent`. * - * @param {Object} error The error that generated this event - * @param {WebSocket} target A reference to the target to which the event was - * dispatched + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.data=null] The message content */ - constructor(error, target) { - super('error', target); + constructor(type, options = {}) { + super(type); - this.message = error.message; - this.error = error; + this[kData] = options.data === undefined ? null : options.data; + } + + /** + * @type {*} + */ + get data() { + return this[kData]; } } +Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true }); + /** * This provides methods for emulating the `EventTarget` interface. It's not * meant to be used directly. @@ -120,46 +181,62 @@ const EventTarget = { * @param {Function} listener The listener to add * @param {Object} [options] An options object specifies characteristics about * the event listener - * @param {Boolean} [options.once=false] A `Boolean`` indicating that the + * @param {Boolean} [options.once=false] A `Boolean` indicating that the * listener should be invoked at most once after being added. If `true`, * the listener would be automatically removed when invoked. * @public */ - addEventListener(type, listener, options) { - if (typeof listener !== 'function') return; + addEventListener(type, listener, options = {}) { + let wrapper; - function onMessage(data) { - listener.call(this, new MessageEvent(data, this)); - } + if (type === 'message') { + wrapper = function onMessage(data, isBinary) { + const event = new MessageEvent('message', { + data: isBinary ? data : data.toString() + }); - function onClose(code, message) { - listener.call(this, new CloseEvent(code, message, this)); - } + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === 'close') { + wrapper = function onClose(code, message) { + const event = new CloseEvent('close', { + code, + reason: message.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent + }); - function onError(error) { - listener.call(this, new ErrorEvent(error, this)); - } + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === 'error') { + wrapper = function onError(error) { + const event = new ErrorEvent('error', { + error, + message: error.message + }); - function onOpen() { - listener.call(this, new OpenEvent(this)); + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === 'open') { + wrapper = function onOpen() { + const event = new Event('open'); + + event[kTarget] = this; + listener.call(this, event); + }; + } else { + return; } - const method = options && options.once ? 'once' : 'on'; + wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute]; + wrapper[kListener] = listener; - if (type === 'message') { - onMessage._listener = listener; - this[method](type, onMessage); - } else if (type === 'close') { - onClose._listener = listener; - this[method](type, onClose); - } else if (type === 'error') { - onError._listener = listener; - this[method](type, onError); - } else if (type === 'open') { - onOpen._listener = listener; - this[method](type, onOpen); + if (options.once) { + this.once(type, wrapper); } else { - this[method](type, listener); + this.on(type, wrapper); } }, @@ -167,18 +244,23 @@ const EventTarget = { * Remove an event listener. * * @param {String} type A string representing the event type to remove - * @param {Function} listener The listener to remove + * @param {Function} handler The listener to remove * @public */ - removeEventListener(type, listener) { - const listeners = this.listeners(type); - - for (let i = 0; i < listeners.length; i++) { - if (listeners[i] === listener || listeners[i]._listener === listener) { - this.removeListener(type, listeners[i]); + removeEventListener(type, handler) { + for (const listener of this.listeners(type)) { + if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { + this.removeListener(type, listener); + break; } } } }; -module.exports = EventTarget; +module.exports = { + CloseEvent, + ErrorEvent, + Event, + EventTarget, + MessageEvent +}; diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/extension.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/extension.js index 87a421329d4..3d7895c1b06 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/extension.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/extension.js @@ -1,27 +1,6 @@ 'use strict'; -// -// Allowed token characters: -// -// '!', '#', '$', '%', '&', ''', '*', '+', '-', -// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' -// -// tokenChars[32] === 0 // ' ' -// tokenChars[33] === 1 // '!' -// tokenChars[34] === 0 // '"' -// ... -// -// prettier-ignore -const tokenChars = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 - 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 -]; +const { tokenChars } = require('./validation'); /** * Adds an offer to the map of extension offers or a parameter to the map of @@ -47,9 +26,6 @@ function push(dest, name, elem) { */ function parse(header) { const offers = Object.create(null); - - if (header === undefined || header === '') return offers; - let params = Object.create(null); let mustUnescape = false; let isEscaping = false; @@ -57,16 +33,20 @@ function parse(header) { let extensionName; let paramName; let start = -1; + let code = -1; let end = -1; let i = 0; for (; i < header.length; i++) { - const code = header.charCodeAt(i); + code = header.charCodeAt(i); if (extensionName === undefined) { if (end === -1 && tokenChars[code] === 1) { if (start === -1) start = i; - } else if (code === 0x20 /* ' ' */ || code === 0x09 /* '\t' */) { + } else if ( + i !== 0 && + (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ + ) { if (end === -1 && start !== -1) end = i; } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) { if (start === -1) { @@ -167,7 +147,7 @@ function parse(header) { } } - if (start === -1 || inQuotes) { + if (start === -1 || inQuotes || code === 0x20 || code === 0x09) { throw new SyntaxError('Unexpected end of input'); } diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/permessage-deflate.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/permessage-deflate.js index ce91784295c..50406971922 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/permessage-deflate.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/permessage-deflate.js @@ -4,7 +4,7 @@ const zlib = require('zlib'); const bufferUtil = require('./buffer-util'); const Limiter = require('./limiter'); -const { kStatusCode, NOOP } = require('./constants'); +const { kStatusCode } = require('./constants'); const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); const kPerMessageDeflate = Symbol('permessage-deflate'); @@ -30,22 +30,22 @@ class PerMessageDeflate { * Creates a PerMessageDeflate instance. * * @param {Object} [options] Configuration options - * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept - * disabling of server context takeover + * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support + * for, or request, a custom client window size * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ * acknowledge disabling of client context takeover + * @param {Number} [options.concurrencyLimit=10] The number of concurrent + * calls to zlib * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the * use of a custom server window size - * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support - * for, or request, a custom client window size + * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept + * disabling of server context takeover + * @param {Number} [options.threshold=1024] Size (in bytes) below which + * messages should not be compressed if context takeover is disabled * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on * deflate * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on * inflate - * @param {Number} [options.threshold=1024] Size (in bytes) below which - * messages should not be compressed - * @param {Number} [options.concurrencyLimit=10] The number of concurrent - * calls to zlib * @param {Boolean} [isServer=false] Create the instance in either server or * client mode * @param {Number} [maxPayload=0] The maximum allowed message length @@ -418,13 +418,6 @@ class PerMessageDeflate { this._deflate[kTotalLength] = 0; this._deflate[kBuffers] = []; - // - // An `'error'` event is emitted, only on Node.js < 10.0.0, if the - // `zlib.DeflateRaw` instance is closed while data is being processed. - // This can happen if `PerMessageDeflate#cleanup()` is called at the wrong - // time due to an abnormal WebSocket closure. - // - this._deflate.on('error', NOOP); this._deflate.on('data', deflateOnData); } diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/receiver.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/receiver.js index 1d2af76e1f2..2d29d62bb08 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/receiver.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/receiver.js @@ -28,20 +28,25 @@ class Receiver extends Writable { /** * Creates a Receiver instance. * - * @param {String} [binaryType=nodebuffer] The type for binary data - * @param {Object} [extensions] An object containing the negotiated extensions - * @param {Boolean} [isServer=false] Specifies whether to operate in client or - * server mode - * @param {Number} [maxPayload=0] The maximum allowed message length + * @param {Object} [options] Options object + * @param {String} [options.binaryType=nodebuffer] The type for binary data + * @param {Object} [options.extensions] An object containing the negotiated + * extensions + * @param {Boolean} [options.isServer=false] Specifies whether to operate in + * client or server mode + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages */ - constructor(binaryType, extensions, isServer, maxPayload) { + constructor(options = {}) { super(); - this._binaryType = binaryType || BINARY_TYPES[0]; + this._binaryType = options.binaryType || BINARY_TYPES[0]; + this._extensions = options.extensions || {}; + this._isServer = !!options.isServer; + this._maxPayload = options.maxPayload | 0; + this._skipUTF8Validation = !!options.skipUTF8Validation; this[kWebSocket] = undefined; - this._extensions = extensions || {}; - this._isServer = !!isServer; - this._maxPayload = maxPayload | 0; this._bufferedBytes = 0; this._buffers = []; @@ -412,7 +417,13 @@ class Receiver extends Writable { } data = this.consume(this._payloadLength); - if (this._masked) unmask(data, this._mask); + + if ( + this._masked && + (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0 + ) { + unmask(data, this._mask); + } } if (this._opcode > 0x07) return this.controlMessage(data); @@ -425,7 +436,7 @@ class Receiver extends Writable { if (data.length) { // - // This message is not compressed so its lenght is the sum of the payload + // This message is not compressed so its length is the sum of the payload // length of all fragments. // this._messageLength = this._totalPayloadLength; @@ -499,11 +510,11 @@ class Receiver extends Writable { data = fragments; } - this.emit('message', data); + this.emit('message', data, true); } else { const buf = concat(fragments, messageLength); - if (!isValidUTF8(buf)) { + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { this._loop = false; return error( Error, @@ -514,7 +525,7 @@ class Receiver extends Writable { ); } - this.emit('message', buf.toString()); + this.emit('message', buf, false); } } @@ -533,7 +544,7 @@ class Receiver extends Writable { this._loop = false; if (data.length === 0) { - this.emit('conclude', 1005, ''); + this.emit('conclude', 1005, EMPTY_BUFFER); this.end(); } else if (data.length === 1) { return error( @@ -558,7 +569,7 @@ class Receiver extends Writable { const buf = data.slice(2); - if (!isValidUTF8(buf)) { + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { return error( Error, 'invalid UTF-8 sequence', @@ -568,7 +579,7 @@ class Receiver extends Writable { ); } - this.emit('conclude', code, buf.toString()); + this.emit('conclude', code, buf); this.end(); } } else if (this._opcode === 0x09) { diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/sender.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/sender.js index 441171c5795..2417656d706 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/sender.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/sender.js @@ -11,7 +11,7 @@ const { EMPTY_BUFFER } = require('./constants'); const { isValidStatusCode } = require('./validation'); const { mask: applyMask, toBuffer } = require('./buffer-util'); -const mask = Buffer.alloc(4); +const maskBuffer = Buffer.alloc(4); /** * HyBi Sender implementation. @@ -22,9 +22,17 @@ class Sender { * * @param {(net.Socket|tls.Socket)} socket The connection socket * @param {Object} [extensions] An object containing the negotiated extensions + * @param {Function} [generateMask] The function used to generate the masking + * key */ - constructor(socket, extensions) { + constructor(socket, extensions, generateMask) { this._extensions = extensions || {}; + + if (generateMask) { + this._generateMask = generateMask; + this._maskBuffer = Buffer.alloc(4); + } + this._socket = socket; this._firstFragment = true; @@ -40,21 +48,43 @@ class Sender { * * @param {Buffer} data The data to frame * @param {Object} options Options object - * @param {Number} options.opcode The opcode - * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be - * modified * @param {Boolean} [options.fin=false] Specifies whether or not to set the * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key * @param {Boolean} [options.mask=false] Specifies whether or not to mask * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the * RSV1 bit * @return {Buffer[]} The framed data as a list of `Buffer` instances * @public */ static frame(data, options) { - const merge = options.mask && options.readOnly; - let offset = options.mask ? 6 : 2; + let mask; + let merge = false; + let offset = 2; + let skipMasking = false; + + if (options.mask) { + mask = options.maskBuffer || maskBuffer; + + if (options.generateMask) { + options.generateMask(mask); + } else { + randomFillSync(mask, 0, 4); + } + + skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; + if (options.readOnly && !skipMasking) merge = true; + + offset = 6; + } + let payloadLength = data.length; if (data.length >= 65536) { @@ -75,20 +105,20 @@ class Sender { if (payloadLength === 126) { target.writeUInt16BE(data.length, 2); } else if (payloadLength === 127) { - target.writeUInt32BE(0, 2); - target.writeUInt32BE(data.length, 6); + target[2] = target[3] = 0; + target.writeUIntBE(data.length, 4, 6); } if (!options.mask) return [target, data]; - randomFillSync(mask, 0, 4); - target[1] |= 0x80; target[offset - 4] = mask[0]; target[offset - 3] = mask[1]; target[offset - 2] = mask[2]; target[offset - 1] = mask[3]; + if (skipMasking) return [target, data]; + if (merge) { applyMask(data, mask, target, offset, data.length); return [target]; @@ -102,7 +132,7 @@ class Sender { * Sends a close message to the other peer. * * @param {Number} [code] The status code component of the body - * @param {String} [data] The message component of the body + * @param {(String|Buffer)} [data] The message component of the body * @param {Boolean} [mask=false] Specifies whether or not to mask the message * @param {Function} [cb] Callback * @public @@ -114,7 +144,7 @@ class Sender { buf = EMPTY_BUFFER; } else if (typeof code !== 'number' || !isValidStatusCode(code)) { throw new TypeError('First argument must be a valid error code number'); - } else if (data === undefined || data === '') { + } else if (data === undefined || !data.length) { buf = Buffer.allocUnsafe(2); buf.writeUInt16BE(code, 0); } else { @@ -126,7 +156,12 @@ class Sender { buf = Buffer.allocUnsafe(2 + length); buf.writeUInt16BE(code, 0); - buf.write(data, 2); + + if (typeof data === 'string') { + buf.write(data, 2); + } else { + buf.set(data, 2); + } } if (this._deflating) { @@ -151,6 +186,8 @@ class Sender { rsv1: false, opcode: 0x08, mask, + maskBuffer: this._maskBuffer, + generateMask: this._generateMask, readOnly: false }), cb @@ -195,6 +232,8 @@ class Sender { rsv1: false, opcode: 0x09, mask, + maskBuffer: this._maskBuffer, + generateMask: this._generateMask, readOnly }), cb @@ -239,6 +278,8 @@ class Sender { rsv1: false, opcode: 0x0a, mask, + maskBuffer: this._maskBuffer, + generateMask: this._generateMask, readOnly }), cb @@ -250,10 +291,10 @@ class Sender { * * @param {*} data The message to send * @param {Object} options Options object - * @param {Boolean} [options.compress=false] Specifies whether or not to - * compress `data` * @param {Boolean} [options.binary=false] Specifies whether `data` is binary * or text + * @param {Boolean} [options.compress=false] Specifies whether or not to + * compress `data` * @param {Boolean} [options.fin=false] Specifies whether the fragment is the * last one * @param {Boolean} [options.mask=false] Specifies whether or not to mask @@ -269,7 +310,15 @@ class Sender { if (this._firstFragment) { this._firstFragment = false; - if (rsv1 && perMessageDeflate) { + if ( + rsv1 && + perMessageDeflate && + perMessageDeflate.params[ + perMessageDeflate._isServer + ? 'server_no_context_takeover' + : 'client_no_context_takeover' + ] + ) { rsv1 = buf.length >= perMessageDeflate._threshold; } this._compress = rsv1; @@ -286,6 +335,8 @@ class Sender { rsv1, opcode, mask: options.mask, + maskBuffer: this._maskBuffer, + generateMask: this._generateMask, readOnly: toBuffer.readOnly }; @@ -301,6 +352,8 @@ class Sender { rsv1: false, opcode, mask: options.mask, + maskBuffer: this._maskBuffer, + generateMask: this._generateMask, readOnly: toBuffer.readOnly }), cb @@ -316,12 +369,16 @@ class Sender { * `data` * @param {Object} options Options object * @param {Number} options.opcode The opcode - * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be - * modified * @param {Boolean} [options.fin=false] Specifies whether or not to set the * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key * @param {Boolean} [options.mask=false] Specifies whether or not to mask * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the * RSV1 bit * @param {Function} [cb] Callback diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/stream.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/stream.js index b0896ff8394..230734b79a8 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/stream.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/stream.js @@ -47,23 +47,8 @@ function duplexOnError(err) { * @public */ function createWebSocketStream(ws, options) { - let resumeOnReceiverDrain = true; let terminateOnDestroy = true; - function receiverOnDrain() { - if (resumeOnReceiverDrain) ws._socket.resume(); - } - - if (ws.readyState === ws.CONNECTING) { - ws.once('open', function open() { - ws._receiver.removeAllListeners('drain'); - ws._receiver.on('drain', receiverOnDrain); - }); - } else { - ws._receiver.removeAllListeners('drain'); - ws._receiver.on('drain', receiverOnDrain); - } - const duplex = new Duplex({ ...options, autoDestroy: false, @@ -72,11 +57,11 @@ function createWebSocketStream(ws, options) { writableObjectMode: false }); - ws.on('message', function message(msg) { - if (!duplex.push(msg)) { - resumeOnReceiverDrain = false; - ws._socket.pause(); - } + ws.on('message', function message(msg, isBinary) { + const data = + !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; + + if (!duplex.push(data)) ws.pause(); }); ws.once('error', function error(err) { @@ -152,10 +137,7 @@ function createWebSocketStream(ws, options) { }; duplex._read = function () { - if (ws.readyState === ws.OPEN && !resumeOnReceiverDrain) { - resumeOnReceiverDrain = true; - if (!ws._receiver._writableState.needDrain) ws._socket.resume(); - } + if (ws.isPaused) ws.resume(); }; duplex._write = function (chunk, encoding, callback) { diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/subprotocol.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/subprotocol.js new file mode 100644 index 00000000000..d4381e8864f --- /dev/null +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/subprotocol.js @@ -0,0 +1,62 @@ +'use strict'; + +const { tokenChars } = require('./validation'); + +/** + * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names. + * + * @param {String} header The field value of the header + * @return {Set} The subprotocol names + * @public + */ +function parse(header) { + const protocols = new Set(); + let start = -1; + let end = -1; + let i = 0; + + for (i; i < header.length; i++) { + const code = header.charCodeAt(i); + + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if ( + i !== 0 && + (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ + ) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x2c /* ',' */) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + + const protocol = header.slice(start, end); + + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + + protocols.add(protocol); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + + if (start === -1 || end !== -1) { + throw new SyntaxError('Unexpected end of input'); + } + + const protocol = header.slice(start, i); + + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + + protocols.add(protocol); + return protocols; +} + +module.exports = { parse }; diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/validation.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/validation.js index 169ac6f0631..ed98c75911f 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/validation.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/validation.js @@ -1,5 +1,28 @@ 'use strict'; +// +// Allowed token characters: +// +// '!', '#', '$', '%', '&', ''', '*', '+', '-', +// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' +// +// tokenChars[32] === 0 // ' ' +// tokenChars[33] === 1 // '!' +// tokenChars[34] === 0 // '"' +// ... +// +// prettier-ignore +const tokenChars = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 +]; + /** * Checks if a status code is allowed in a close frame. * @@ -83,22 +106,19 @@ function _isValidUTF8(buf) { } try { - let isValidUTF8 = require('utf-8-validate'); - - /* istanbul ignore if */ - if (typeof isValidUTF8 === 'object') { - isValidUTF8 = isValidUTF8.Validation.isValidUTF8; // utf-8-validate@<3.0.0 - } + const isValidUTF8 = require('utf-8-validate'); module.exports = { isValidStatusCode, isValidUTF8(buf) { return buf.length < 150 ? _isValidUTF8(buf) : isValidUTF8(buf); - } + }, + tokenChars }; } catch (e) /* istanbul ignore next */ { module.exports = { isValidStatusCode, - isValidUTF8: _isValidUTF8 + isValidUTF8: _isValidUTF8, + tokenChars }; } diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket-server.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket-server.js index fe7fdf501ce..3c7939f28af 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket-server.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket-server.js @@ -9,9 +9,10 @@ const net = require('net'); const tls = require('tls'); const { createHash } = require('crypto'); +const extension = require('./extension'); const PerMessageDeflate = require('./permessage-deflate'); +const subprotocol = require('./subprotocol'); const WebSocket = require('./websocket'); -const { format, parse } = require('./extension'); const { GUID, kWebSocket } = require('./constants'); const keyRegex = /^[+/0-9A-Za-z]{22}==$/; @@ -45,6 +46,8 @@ class WebSocketServer extends EventEmitter { * @param {Number} [options.port] The port where to bind the server * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S * server to use + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages * @param {Function} [options.verifyClient] A hook to reject connections * @param {Function} [callback] A listener for the `listening` event */ @@ -53,6 +56,7 @@ class WebSocketServer extends EventEmitter { options = { maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, perMessageDeflate: false, handleProtocols: null, clientTracking: true, @@ -110,7 +114,11 @@ class WebSocketServer extends EventEmitter { } if (options.perMessageDeflate === true) options.perMessageDeflate = {}; - if (options.clientTracking) this.clients = new Set(); + if (options.clientTracking) { + this.clients = new Set(); + this._shouldEmitClose = false; + } + this.options = options; this._state = RUNNING; } @@ -134,45 +142,58 @@ class WebSocketServer extends EventEmitter { } /** - * Close the server. + * Stop the server from accepting new connections and emit the `'close'` event + * when all existing connections are closed. * - * @param {Function} [cb] Callback + * @param {Function} [cb] A one-time listener for the `'close'` event * @public */ close(cb) { - if (cb) this.once('close', cb); - if (this._state === CLOSED) { + if (cb) { + this.once('close', () => { + cb(new Error('The server is not running')); + }); + } + process.nextTick(emitClose, this); return; } + if (cb) this.once('close', cb); + if (this._state === CLOSING) return; this._state = CLOSING; - // - // Terminate all associated clients. - // - if (this.clients) { - for (const client of this.clients) client.terminate(); - } + if (this.options.noServer || this.options.server) { + if (this._server) { + this._removeListeners(); + this._removeListeners = this._server = null; + } - const server = this._server; + if (this.clients) { + if (!this.clients.size) { + process.nextTick(emitClose, this); + } else { + this._shouldEmitClose = true; + } + } else { + process.nextTick(emitClose, this); + } + } else { + const server = this._server; - if (server) { this._removeListeners(); this._removeListeners = this._server = null; // - // Close the http server if it was internally created. + // The HTTP/S server was created internally. Close it, and rely on its + // `'close'` event. // - if (this.options.port != null) { - server.close(emitClose.bind(undefined, this)); - return; - } + server.close(() => { + emitClose(this); + }); } - - process.nextTick(emitClose, this); } /** @@ -208,10 +229,9 @@ class WebSocketServer extends EventEmitter { const key = req.headers['sec-websocket-key'] !== undefined - ? req.headers['sec-websocket-key'].trim() + ? req.headers['sec-websocket-key'] : false; const version = +req.headers['sec-websocket-version']; - const extensions = {}; if ( req.method !== 'GET' || @@ -224,7 +244,24 @@ class WebSocketServer extends EventEmitter { return abortHandshake(socket, 400); } - if (this.options.perMessageDeflate) { + const secWebSocketProtocol = req.headers['sec-websocket-protocol']; + let protocols = new Set(); + + if (secWebSocketProtocol !== undefined) { + try { + protocols = subprotocol.parse(secWebSocketProtocol); + } catch (err) { + return abortHandshake(socket, 400); + } + } + + const secWebSocketExtensions = req.headers['sec-websocket-extensions']; + const extensions = {}; + + if ( + this.options.perMessageDeflate && + secWebSocketExtensions !== undefined + ) { const perMessageDeflate = new PerMessageDeflate( this.options.perMessageDeflate, true, @@ -232,7 +269,7 @@ class WebSocketServer extends EventEmitter { ); try { - const offers = parse(req.headers['sec-websocket-extensions']); + const offers = extension.parse(secWebSocketExtensions); if (offers[PerMessageDeflate.extensionName]) { perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); @@ -260,7 +297,15 @@ class WebSocketServer extends EventEmitter { return abortHandshake(socket, code || 401, message, headers); } - this.completeUpgrade(key, extensions, req, socket, head, cb); + this.completeUpgrade( + extensions, + key, + protocols, + req, + socket, + head, + cb + ); }); return; } @@ -268,14 +313,15 @@ class WebSocketServer extends EventEmitter { if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); } - this.completeUpgrade(key, extensions, req, socket, head, cb); + this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); } /** * Upgrade the connection to WebSocket. * - * @param {String} key The value of the `Sec-WebSocket-Key` header * @param {Object} extensions The accepted extensions + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Set} protocols The subprotocols * @param {http.IncomingMessage} req The request object * @param {(net.Socket|tls.Socket)} socket The network socket between the * server and client @@ -284,7 +330,7 @@ class WebSocketServer extends EventEmitter { * @throws {Error} If called more than once with the same socket * @private */ - completeUpgrade(key, extensions, req, socket, head, cb) { + completeUpgrade(extensions, key, protocols, req, socket, head, cb) { // // Destroy the socket if the client has already sent a FIN packet. // @@ -311,19 +357,14 @@ class WebSocketServer extends EventEmitter { ]; const ws = new WebSocket(null); - let protocol = req.headers['sec-websocket-protocol']; - - if (protocol) { - protocol = protocol.split(',').map(trim); + if (protocols.size) { // // Optionally call external protocol selection handler. // - if (this.options.handleProtocols) { - protocol = this.options.handleProtocols(protocol, req); - } else { - protocol = protocol[0]; - } + const protocol = this.options.handleProtocols + ? this.options.handleProtocols(protocols, req) + : protocols.values().next().value; if (protocol) { headers.push(`Sec-WebSocket-Protocol: ${protocol}`); @@ -333,7 +374,7 @@ class WebSocketServer extends EventEmitter { if (extensions[PerMessageDeflate.extensionName]) { const params = extensions[PerMessageDeflate.extensionName].params; - const value = format({ + const value = extension.format({ [PerMessageDeflate.extensionName]: [params] }); headers.push(`Sec-WebSocket-Extensions: ${value}`); @@ -348,11 +389,20 @@ class WebSocketServer extends EventEmitter { socket.write(headers.concat('\r\n').join('\r\n')); socket.removeListener('error', socketOnError); - ws.setSocket(socket, head, this.options.maxPayload); + ws.setSocket(socket, head, { + maxPayload: this.options.maxPayload, + skipUTF8Validation: this.options.skipUTF8Validation + }); if (this.clients) { this.clients.add(ws); - ws.on('close', () => this.clients.delete(ws)); + ws.on('close', () => { + this.clients.delete(ws); + + if (this._shouldEmitClose && !this.clients.size) { + process.nextTick(emitClose, this); + } + }); } cb(ws, req); @@ -433,15 +483,3 @@ function abortHandshake(socket, code, message, headers) { socket.removeListener('error', socketOnError); socket.destroy(); } - -/** - * Remove whitespace characters from both ends of a string. - * - * @param {String} str The string - * @return {String} A new string representing `str` stripped of whitespace - * characters from both its beginning and end - * @private - */ -function trim(str) { - return str.trim(); -} diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket.js b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket.js index 7f1e3bcfae8..57710f4e125 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket.js +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/lib/websocket.js @@ -1,3 +1,5 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */ + 'use strict'; const EventEmitter = require('events'); @@ -6,6 +8,7 @@ const http = require('http'); const net = require('net'); const tls = require('tls'); const { randomBytes, createHash } = require('crypto'); +const { Readable } = require('stream'); const { URL } = require('url'); const PerMessageDeflate = require('./permessage-deflate'); @@ -15,15 +18,20 @@ const { BINARY_TYPES, EMPTY_BUFFER, GUID, + kForOnEventAttribute, + kListener, kStatusCode, kWebSocket, NOOP } = require('./constants'); -const { addEventListener, removeEventListener } = require('./event-target'); +const { + EventTarget: { addEventListener, removeEventListener } +} = require('./event-target'); const { format, parse } = require('./extension'); const { toBuffer } = require('./buffer-util'); const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; const protocolVersions = [8, 13]; const closeTimeout = 30 * 1000; @@ -47,9 +55,10 @@ class WebSocket extends EventEmitter { this._closeCode = 1006; this._closeFrameReceived = false; this._closeFrameSent = false; - this._closeMessage = ''; + this._closeMessage = EMPTY_BUFFER; this._closeTimer = null; this._extensions = {}; + this._paused = false; this._protocol = ''; this._readyState = WebSocket.CONNECTING; this._receiver = null; @@ -61,11 +70,15 @@ class WebSocket extends EventEmitter { this._isServer = false; this._redirects = 0; - if (Array.isArray(protocols)) { - protocols = protocols.join(', '); - } else if (typeof protocols === 'object' && protocols !== null) { - options = protocols; - protocols = undefined; + if (protocols === undefined) { + protocols = []; + } else if (!Array.isArray(protocols)) { + if (typeof protocols === 'object' && protocols !== null) { + options = protocols; + protocols = []; + } else { + protocols = [protocols]; + } } initAsClient(this, address, protocols, options); @@ -113,49 +126,44 @@ class WebSocket extends EventEmitter { } /** + * @type {Boolean} + */ + get isPaused() { + return this._paused; + } + + /** * @type {Function} */ /* istanbul ignore next */ get onclose() { - return undefined; + return null; } - /* istanbul ignore next */ - set onclose(listener) {} - /** * @type {Function} */ /* istanbul ignore next */ get onerror() { - return undefined; + return null; } - /* istanbul ignore next */ - set onerror(listener) {} - /** * @type {Function} */ /* istanbul ignore next */ get onopen() { - return undefined; + return null; } - /* istanbul ignore next */ - set onopen(listener) {} - /** * @type {Function} */ /* istanbul ignore next */ get onmessage() { - return undefined; + return null; } - /* istanbul ignore next */ - set onmessage(listener) {} - /** * @type {String} */ @@ -183,18 +191,24 @@ class WebSocket extends EventEmitter { * @param {(net.Socket|tls.Socket)} socket The network socket between the * server and client * @param {Buffer} head The first packet of the upgraded stream - * @param {Number} [maxPayload=0] The maximum allowed message size + * @param {Object} options Options object + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.maxPayload=0] The maximum allowed message size + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages * @private */ - setSocket(socket, head, maxPayload) { - const receiver = new Receiver( - this.binaryType, - this._extensions, - this._isServer, - maxPayload - ); + setSocket(socket, head, options) { + const receiver = new Receiver({ + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxPayload: options.maxPayload, + skipUTF8Validation: options.skipUTF8Validation + }); - this._sender = new Sender(socket, this._extensions); + this._sender = new Sender(socket, this._extensions, options.generateMask); this._receiver = receiver; this._socket = socket; @@ -259,7 +273,8 @@ class WebSocket extends EventEmitter { * +---+ * * @param {Number} [code] Status code explaining why the connection is closing - * @param {String} [data] A string explaining why the connection is closing + * @param {(String|Buffer)} [data] The reason why the connection is + * closing * @public */ close(code, data) { @@ -308,6 +323,23 @@ class WebSocket extends EventEmitter { } /** + * Pause the socket. + * + * @public + */ + pause() { + if ( + this.readyState === WebSocket.CONNECTING || + this.readyState === WebSocket.CLOSED + ) { + return; + } + + this._paused = true; + this._socket.pause(); + } + + /** * Send a ping. * * @param {*} [data] The data to send @@ -372,14 +404,31 @@ class WebSocket extends EventEmitter { } /** + * Resume the socket. + * + * @public + */ + resume() { + if ( + this.readyState === WebSocket.CONNECTING || + this.readyState === WebSocket.CLOSED + ) { + return; + } + + this._paused = false; + if (!this._receiver._writableState.needDrain) this._socket.resume(); + } + + /** * Send a data message. * * @param {*} data The message to send * @param {Object} [options] Options object - * @param {Boolean} [options.compress] Specifies whether or not to compress - * `data` * @param {Boolean} [options.binary] Specifies whether `data` is binary or * text + * @param {Boolean} [options.compress] Specifies whether or not to compress + * `data` * @param {Boolean} [options.fin=true] Specifies whether the fragment is the * last one * @param {Boolean} [options.mask] Specifies whether or not to mask `data` @@ -513,6 +562,7 @@ Object.defineProperty(WebSocket.prototype, 'CLOSED', { 'binaryType', 'bufferedAmount', 'extensions', + 'isPaused', 'protocol', 'readyState', 'url' @@ -528,22 +578,25 @@ Object.defineProperty(WebSocket.prototype, 'CLOSED', { Object.defineProperty(WebSocket.prototype, `on${method}`, { enumerable: true, get() { - const listeners = this.listeners(method); - for (let i = 0; i < listeners.length; i++) { - if (listeners[i]._listener) return listeners[i]._listener; + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) return listener[kListener]; } - return undefined; + return null; }, - set(listener) { - const listeners = this.listeners(method); - for (let i = 0; i < listeners.length; i++) { - // - // Remove only the listeners added via `addEventListener`. - // - if (listeners[i]._listener) this.removeListener(method, listeners[i]); + set(handler) { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) { + this.removeListener(method, listener); + break; + } } - this.addEventListener(method, listener); + + if (typeof handler !== 'function') return; + + this.addEventListener(method, handler, { + [kForOnEventAttribute]: true + }); } }); }); @@ -558,28 +611,33 @@ module.exports = WebSocket; * * @param {WebSocket} websocket The client to initialize * @param {(String|URL)} address The URL to which to connect - * @param {String} [protocols] The subprotocols + * @param {Array} protocols The subprotocols * @param {Object} [options] Connection options - * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable - * permessage-deflate + * @param {Boolean} [options.followRedirects=false] Whether or not to follow + * redirects + * @param {Function} [options.generateMask] The function used to generate the + * masking key * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the * handshake request - * @param {Number} [options.protocolVersion=13] Value of the - * `Sec-WebSocket-Version` header - * @param {String} [options.origin] Value of the `Origin` or - * `Sec-WebSocket-Origin` header * @param {Number} [options.maxPayload=104857600] The maximum allowed message * size - * @param {Boolean} [options.followRedirects=false] Whether or not to follow - * redirects * @param {Number} [options.maxRedirects=10] The maximum number of redirects * allowed + * @param {String} [options.origin] Value of the `Origin` or + * `Sec-WebSocket-Origin` header + * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable + * permessage-deflate + * @param {Number} [options.protocolVersion=13] Value of the + * `Sec-WebSocket-Version` header + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages * @private */ function initAsClient(websocket, address, protocols, options) { const opts = { protocolVersion: protocolVersions[1], maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, perMessageDeflate: true, followRedirects: false, maxRedirects: 10, @@ -608,21 +666,43 @@ function initAsClient(websocket, address, protocols, options) { parsedUrl = address; websocket._url = address.href; } else { - parsedUrl = new URL(address); + try { + parsedUrl = new URL(address); + } catch (e) { + throw new SyntaxError(`Invalid URL: ${address}`); + } + websocket._url = address; } + const isSecure = parsedUrl.protocol === 'wss:'; const isUnixSocket = parsedUrl.protocol === 'ws+unix:'; + let invalidURLMessage; + + if (parsedUrl.protocol !== 'ws:' && !isSecure && !isUnixSocket) { + invalidURLMessage = + 'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"'; + } else if (isUnixSocket && !parsedUrl.pathname) { + invalidURLMessage = "The URL's pathname is empty"; + } else if (parsedUrl.hash) { + invalidURLMessage = 'The URL contains a fragment identifier'; + } - if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) { - throw new Error(`Invalid URL: ${websocket.url}`); + if (invalidURLMessage) { + const err = new SyntaxError(invalidURLMessage); + + if (websocket._redirects === 0) { + throw err; + } else { + emitErrorAndClose(websocket, err); + return; + } } - const isSecure = - parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:'; const defaultPort = isSecure ? 443 : 80; const key = randomBytes(16).toString('base64'); const get = isSecure ? https.get : http.get; + const protocolSet = new Set(); let perMessageDeflate; opts.createConnection = isSecure ? tlsConnect : netConnect; @@ -651,8 +731,22 @@ function initAsClient(websocket, address, protocols, options) { [PerMessageDeflate.extensionName]: perMessageDeflate.offer() }); } - if (protocols) { - opts.headers['Sec-WebSocket-Protocol'] = protocols; + if (protocols.length) { + for (const protocol of protocols) { + if ( + typeof protocol !== 'string' || + !subprotocolRegex.test(protocol) || + protocolSet.has(protocol) + ) { + throw new SyntaxError( + 'An invalid or duplicated subprotocol was specified' + ); + } + + protocolSet.add(protocol); + } + + opts.headers['Sec-WebSocket-Protocol'] = protocols.join(','); } if (opts.origin) { if (opts.protocolVersion < 13) { @@ -684,9 +778,7 @@ function initAsClient(websocket, address, protocols, options) { if (req === null || req.aborted) return; req = websocket._req = null; - websocket._readyState = WebSocket.CLOSING; - websocket.emit('error', err); - websocket.emitClose(); + emitErrorAndClose(websocket, err); }); req.on('response', (res) => { @@ -706,7 +798,15 @@ function initAsClient(websocket, address, protocols, options) { req.abort(); - const addr = new URL(location, address); + let addr; + + try { + addr = new URL(location, address); + } catch (e) { + const err = new SyntaxError(`Invalid URL: ${location}`); + emitErrorAndClose(websocket, err); + return; + } initAsClient(websocket, addr, protocols, options); } else if (!websocket.emit('unexpected-response', req, res)) { @@ -739,15 +839,16 @@ function initAsClient(websocket, address, protocols, options) { } const serverProt = res.headers['sec-websocket-protocol']; - const protList = (protocols || '').split(/, */); let protError; - if (!protocols && serverProt) { - protError = 'Server sent a subprotocol but none was requested'; - } else if (protocols && !serverProt) { + if (serverProt !== undefined) { + if (!protocolSet.size) { + protError = 'Server sent a subprotocol but none was requested'; + } else if (!protocolSet.has(serverProt)) { + protError = 'Server sent an invalid subprotocol'; + } + } else if (protocolSet.size) { protError = 'Server sent no subprotocol'; - } else if (serverProt && !protList.includes(serverProt)) { - protError = 'Server sent an invalid subprotocol'; } if (protError) { @@ -780,35 +881,49 @@ function initAsClient(websocket, address, protocols, options) { const extensionNames = Object.keys(extensions); - if (extensionNames.length) { - if ( - extensionNames.length !== 1 || - extensionNames[0] !== PerMessageDeflate.extensionName - ) { - const message = - 'Server indicated an extension that was not requested'; - abortHandshake(websocket, socket, message); - return; - } - - try { - perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); - } catch (err) { - const message = 'Invalid Sec-WebSocket-Extensions header'; - abortHandshake(websocket, socket, message); - return; - } + if ( + extensionNames.length !== 1 || + extensionNames[0] !== PerMessageDeflate.extensionName + ) { + const message = 'Server indicated an extension that was not requested'; + abortHandshake(websocket, socket, message); + return; + } - websocket._extensions[PerMessageDeflate.extensionName] = - perMessageDeflate; + try { + perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Extensions header'; + abortHandshake(websocket, socket, message); + return; } + + websocket._extensions[PerMessageDeflate.extensionName] = + perMessageDeflate; } - websocket.setSocket(socket, head, opts.maxPayload); + websocket.setSocket(socket, head, { + generateMask: opts.generateMask, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation + }); }); } /** + * Emit the `'error'` and `'close'` event. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {Error} The error to emit + * @private + */ +function emitErrorAndClose(websocket, err) { + websocket._readyState = WebSocket.CLOSING; + websocket.emit('error', err); + websocket.emitClose(); +} + +/** * Create a `net.Socket` and initiate a connection. * * @param {Object} options Connection options @@ -909,19 +1024,21 @@ function sendAfterClose(websocket, data, cb) { * The listener of the `Receiver` `'conclude'` event. * * @param {Number} code The status code - * @param {String} reason The reason for closing + * @param {Buffer} reason The reason for closing * @private */ function receiverOnConclude(code, reason) { const websocket = this[kWebSocket]; - websocket._socket.removeListener('data', socketOnData); - websocket._socket.resume(); - websocket._closeFrameReceived = true; websocket._closeMessage = reason; websocket._closeCode = code; + if (websocket._socket[kWebSocket] === undefined) return; + + websocket._socket.removeListener('data', socketOnData); + process.nextTick(resume, websocket._socket); + if (code === 1005) websocket.close(); else websocket.close(code, reason); } @@ -932,7 +1049,9 @@ function receiverOnConclude(code, reason) { * @private */ function receiverOnDrain() { - this[kWebSocket]._socket.resume(); + const websocket = this[kWebSocket]; + + if (!websocket.isPaused) websocket._socket.resume(); } /** @@ -944,10 +1063,18 @@ function receiverOnDrain() { function receiverOnError(err) { const websocket = this[kWebSocket]; - websocket._socket.removeListener('data', socketOnData); - websocket._socket.resume(); + if (websocket._socket[kWebSocket] !== undefined) { + websocket._socket.removeListener('data', socketOnData); + + // + // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See + // https://github.com/websockets/ws/issues/1940. + // + process.nextTick(resume, websocket._socket); + + websocket.close(err[kStatusCode]); + } - websocket.close(err[kStatusCode]); websocket.emit('error', err); } @@ -963,11 +1090,12 @@ function receiverOnFinish() { /** * The listener of the `Receiver` `'message'` event. * - * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The message + * @param {Buffer|ArrayBuffer|Buffer[])} data The message + * @param {Boolean} isBinary Specifies whether the message is binary or not * @private */ -function receiverOnMessage(data) { - this[kWebSocket].emit('message', data); +function receiverOnMessage(data, isBinary) { + this[kWebSocket].emit('message', data, isBinary); } /** @@ -994,6 +1122,16 @@ function receiverOnPong(data) { } /** + * Resume a readable stream + * + * @param {Readable} stream The readable stream + * @private + */ +function resume(stream) { + stream.resume(); +} + +/** * The listener of the `net.Socket` `'close'` event. * * @private @@ -1002,10 +1140,13 @@ function socketOnClose() { const websocket = this[kWebSocket]; this.removeListener('close', socketOnClose); + this.removeListener('data', socketOnData); this.removeListener('end', socketOnEnd); websocket._readyState = WebSocket.CLOSING; + let chunk; + // // The close frame might not have been received or the `'end'` event emitted, // for example, if the socket was destroyed due to an error. Ensure that the @@ -1013,13 +1154,19 @@ function socketOnClose() { // it. If the readable side of the socket is in flowing mode then there is no // buffered data as everything has been already written and `readable.read()` // will return `null`. If instead, the socket is paused, any possible buffered - // data will be read as a single chunk and emitted synchronously in a single - // `'data'` event. + // data will be read as a single chunk. // - websocket._socket.read(); + if ( + !this._readableState.endEmitted && + !websocket._closeFrameReceived && + !websocket._receiver._writableState.errorEmitted && + (chunk = websocket._socket.read()) !== null + ) { + websocket._receiver.write(chunk); + } + websocket._receiver.end(); - this.removeListener('data', socketOnData); this[kWebSocket] = undefined; clearTimeout(websocket._closeTimer); diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/package.json b/chromium/third_party/devtools-frontend/src/node_modules/ws/package.json index d6dff1396c8..813155221b1 100644 --- a/chromium/third_party/devtools-frontend/src/node_modules/ws/package.json +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/package.json @@ -1,6 +1,6 @@ { "name": "ws", - "version": "7.5.3", + "version": "8.4.0", "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", "keywords": [ "HyBi", @@ -16,14 +16,19 @@ "author": "Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)", "license": "MIT", "main": "index.js", + "exports": { + "import": "./wrapper.mjs", + "require": "./index.js" + }, "browser": "browser.js", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "files": [ "browser.js", "index.js", - "lib/*.js" + "lib/*.js", + "wrapper.mjs" ], "scripts": { "test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js", @@ -45,10 +50,10 @@ "devDependencies": { "benchmark": "^2.1.4", "bufferutil": "^4.0.1", - "eslint": "^7.2.0", + "eslint": "^8.0.0", "eslint-config-prettier": "^8.1.0", - "eslint-plugin-prettier": "^3.0.1", - "mocha": "^7.0.0", + "eslint-plugin-prettier": "^4.0.0", + "mocha": "^8.4.0", "nyc": "^15.0.0", "prettier": "^2.0.5", "utf-8-validate": "^5.0.2" diff --git a/chromium/third_party/devtools-frontend/src/node_modules/ws/wrapper.mjs b/chromium/third_party/devtools-frontend/src/node_modules/ws/wrapper.mjs new file mode 100644 index 00000000000..7245ad15d02 --- /dev/null +++ b/chromium/third_party/devtools-frontend/src/node_modules/ws/wrapper.mjs @@ -0,0 +1,8 @@ +import createWebSocketStream from './lib/stream.js'; +import Receiver from './lib/receiver.js'; +import Sender from './lib/sender.js'; +import WebSocket from './lib/websocket.js'; +import WebSocketServer from './lib/websocket-server.js'; + +export { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer }; +export default WebSocket; |