aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/node_modules/undici/lib/web/websocket
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/undici/lib/web/websocket')
-rw-r--r--node_modules/undici/lib/web/websocket/permessage-deflate.js52
-rw-r--r--node_modules/undici/lib/web/websocket/receiver.js13
-rw-r--r--node_modules/undici/lib/web/websocket/util.js10
-rw-r--r--node_modules/undici/lib/web/websocket/websocket.js2
4 files changed, 68 insertions, 9 deletions
diff --git a/node_modules/undici/lib/web/websocket/permessage-deflate.js b/node_modules/undici/lib/web/websocket/permessage-deflate.js
index 76cb366..1f1a130 100644
--- a/node_modules/undici/lib/web/websocket/permessage-deflate.js
+++ b/node_modules/undici/lib/web/websocket/permessage-deflate.js
@@ -2,17 +2,30 @@
const { createInflateRaw, Z_DEFAULT_WINDOWBITS } = require('node:zlib')
const { isValidClientWindowBits } = require('./util')
+const { MessageSizeExceededError } = require('../../core/errors')
const tail = Buffer.from([0x00, 0x00, 0xff, 0xff])
const kBuffer = Symbol('kBuffer')
const kLength = Symbol('kLength')
+// Default maximum decompressed message size: 4 MB
+const kDefaultMaxDecompressedSize = 4 * 1024 * 1024
+
class PerMessageDeflate {
/** @type {import('node:zlib').InflateRaw} */
#inflate
#options = {}
+ /** @type {boolean} */
+ #aborted = false
+
+ /** @type {Function|null} */
+ #currentCallback = null
+
+ /**
+ * @param {Map<string, string>} extensions
+ */
constructor (extensions) {
this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover')
this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits')
@@ -24,6 +37,11 @@ class PerMessageDeflate {
// payload of the message.
// 2. Decompress the resulting data using DEFLATE.
+ if (this.#aborted) {
+ callback(new MessageSizeExceededError())
+ return
+ }
+
if (!this.#inflate) {
let windowBits = Z_DEFAULT_WINDOWBITS
@@ -36,13 +54,37 @@ class PerMessageDeflate {
windowBits = Number.parseInt(this.#options.serverMaxWindowBits)
}
- this.#inflate = createInflateRaw({ windowBits })
+ try {
+ this.#inflate = createInflateRaw({ windowBits })
+ } catch (err) {
+ callback(err)
+ return
+ }
this.#inflate[kBuffer] = []
this.#inflate[kLength] = 0
this.#inflate.on('data', (data) => {
- this.#inflate[kBuffer].push(data)
+ if (this.#aborted) {
+ return
+ }
+
this.#inflate[kLength] += data.length
+
+ if (this.#inflate[kLength] > kDefaultMaxDecompressedSize) {
+ this.#aborted = true
+ this.#inflate.removeAllListeners()
+ this.#inflate.destroy()
+ this.#inflate = null
+
+ if (this.#currentCallback) {
+ const cb = this.#currentCallback
+ this.#currentCallback = null
+ cb(new MessageSizeExceededError())
+ }
+ return
+ }
+
+ this.#inflate[kBuffer].push(data)
})
this.#inflate.on('error', (err) => {
@@ -51,16 +93,22 @@ class PerMessageDeflate {
})
}
+ this.#currentCallback = callback
this.#inflate.write(chunk)
if (fin) {
this.#inflate.write(tail)
}
this.#inflate.flush(() => {
+ if (this.#aborted || !this.#inflate) {
+ return
+ }
+
const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength])
this.#inflate[kBuffer].length = 0
this.#inflate[kLength] = 0
+ this.#currentCallback = null
callback(null, full)
})
diff --git a/node_modules/undici/lib/web/websocket/receiver.js b/node_modules/undici/lib/web/websocket/receiver.js
index 581c251..e7f7512 100644
--- a/node_modules/undici/lib/web/websocket/receiver.js
+++ b/node_modules/undici/lib/web/websocket/receiver.js
@@ -37,6 +37,10 @@ class ByteParser extends Writable {
/** @type {Map<string, PerMessageDeflate>} */
#extensions
+ /**
+ * @param {import('./websocket').WebSocket} ws
+ * @param {Map<string, string>|null} extensions
+ */
constructor (ws, extensions) {
super()
@@ -179,6 +183,7 @@ class ByteParser extends Writable {
const buffer = this.consume(8)
const upper = buffer.readUInt32BE(0)
+ const lower = buffer.readUInt32BE(4)
// 2^31 is the maximum bytes an arraybuffer can contain
// on 32-bit systems. Although, on 64-bit systems, this is
@@ -186,14 +191,12 @@ class ByteParser extends Writable {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length
// https://source.chromium.org/chromium/chromium/src/+/main:v8/src/common/globals.h;drc=1946212ac0100668f14eb9e2843bdd846e510a1e;bpv=1;bpt=1;l=1275
// https://source.chromium.org/chromium/chromium/src/+/main:v8/src/objects/js-array-buffer.h;l=34;drc=1946212ac0100668f14eb9e2843bdd846e510a1e
- if (upper > 2 ** 31 - 1) {
+ if (upper !== 0 || lower > 2 ** 31 - 1) {
failWebsocketConnection(this.ws, 'Received payload length > 2^31 bytes.')
return
}
- const lower = buffer.readUInt32BE(4)
-
- this.#info.payloadLength = (upper << 8) + lower
+ this.#info.payloadLength = lower
this.#state = parserStates.READ_DATA
} else if (this.#state === parserStates.READ_DATA) {
if (this.#byteOffset < this.#info.payloadLength) {
@@ -223,7 +226,7 @@ class ByteParser extends Writable {
} else {
this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => {
if (error) {
- closeWebSocketConnection(this.ws, 1007, error.message, error.message.length)
+ failWebsocketConnection(this.ws, error.message)
return
}
diff --git a/node_modules/undici/lib/web/websocket/util.js b/node_modules/undici/lib/web/websocket/util.js
index e5ce789..2a04887 100644
--- a/node_modules/undici/lib/web/websocket/util.js
+++ b/node_modules/undici/lib/web/websocket/util.js
@@ -266,6 +266,12 @@ function parseExtensions (extensions) {
* @param {string} value
*/
function isValidClientWindowBits (value) {
+ // Must have at least one character
+ if (value.length === 0) {
+ return false
+ }
+
+ // Check all characters are ASCII digits
for (let i = 0; i < value.length; i++) {
const byte = value.charCodeAt(i)
@@ -274,7 +280,9 @@ function isValidClientWindowBits (value) {
}
}
- return true
+ // Check numeric range: zlib requires windowBits in range 8-15
+ const num = Number.parseInt(value, 10)
+ return num >= 8 && num <= 15
}
// https://nodejs.org/api/intl.html#detecting-internationalization-support
diff --git a/node_modules/undici/lib/web/websocket/websocket.js b/node_modules/undici/lib/web/websocket/websocket.js
index e405302..aa2a20a 100644
--- a/node_modules/undici/lib/web/websocket/websocket.js
+++ b/node_modules/undici/lib/web/websocket/websocket.js
@@ -431,7 +431,7 @@ class WebSocket extends EventTarget {
* @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
*/
#onConnectionEstablished (response, parsedExtensions) {
- // processResponse is called when the "response’s header list has been received and initialized."
+ // processResponse is called when the "response's header list has been received and initialized."
// once this happens, the connection is open
this[kResponse] = response