Compare commits

..

No commits in common. "main" and "v3.0.0" have entirely different histories.
main ... v3.0.0

16 changed files with 3279 additions and 3684 deletions

View File

@ -3,7 +3,7 @@
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"features": {
"ghcr.io/devcontainers/features/node:2": {},
"ghcr.io/devcontainers/features/docker-in-docker:": {},
"ghcr.io/devcontainers/features/docker-in-docker:3": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"remoteEnv": {

View File

@ -17,7 +17,7 @@ jobs:
persist-credentials: false
- id: setup-node
uses: hoverkraft-tech/ci-github-nodejs/actions/setup-node@df348077afa4e79725151d50606e9dc63f86dcb6 # 0.24.4
uses: hoverkraft-tech/ci-github-nodejs/actions/setup-node@6b74a8f070140f5c120f78026d58e4c00d1b1e37 # 0.24.2
- name: Build dist/ Directory
id: package

View File

@ -7,7 +7,7 @@ permissions: {}
jobs:
test-nodejs:
uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@df348077afa4e79725151d50606e9dc63f86dcb6 # 0.24.4
uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@6b74a8f070140f5c120f78026d58e4c00d1b1e37 # 0.24.2
permissions:
contents: read
id-token: write

View File

@ -7,13 +7,10 @@ permissions: {}
jobs:
linter:
uses: hoverkraft-tech/ci-github-common/.github/workflows/linter.yml@624be17604ee0a7378488191aacb35851e7cf001 # 0.37.1
uses: hoverkraft-tech/ci-github-common/.github/workflows/linter.yml@4bb7594b1bf3696c54b2bbae970376056853f8ea # 0.36.0
permissions:
actions: read
contents: read
issues: write
packages: read
pull-requests: write
security-events: write
statuses: write
with:

View File

@ -10,7 +10,7 @@ permissions: {}
jobs:
greetings:
uses: hoverkraft-tech/ci-github-common/.github/workflows/greetings.yml@624be17604ee0a7378488191aacb35851e7cf001 # 0.37.1
uses: hoverkraft-tech/ci-github-common/.github/workflows/greetings.yml@4bb7594b1bf3696c54b2bbae970376056853f8ea # 0.36.0
permissions:
contents: read
issues: write

View File

@ -23,7 +23,6 @@ jobs:
actions: read
contents: read
id-token: write
issues: write
packages: read
pull-requests: write
security-events: write
@ -67,7 +66,7 @@ jobs:
client-id: ${{ vars.CI_BOT_APP_CLIENT_ID }}
private-key: ${{ secrets.CI_BOT_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] repository automation uses a dedicated app secret without untrusted code execution
- uses: hoverkraft-tech/ci-github-common/actions/create-and-merge-pull-request@624be17604ee0a7378488191aacb35851e7cf001 # 0.37.1
- uses: hoverkraft-tech/ci-github-common/actions/create-and-merge-pull-request@4bb7594b1bf3696c54b2bbae970376056853f8ea # 0.36.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
branch: docs/actions-workflows-documentation-update

View File

@ -20,7 +20,7 @@ permissions: {}
jobs:
main:
uses: hoverkraft-tech/ci-github-common/.github/workflows/need-fix-to-issue.yml@624be17604ee0a7378488191aacb35851e7cf001 # 0.37.1
uses: hoverkraft-tech/ci-github-common/.github/workflows/need-fix-to-issue.yml@4bb7594b1bf3696c54b2bbae970376056853f8ea # 0.36.0
permissions:
contents: read
issues: write

View File

@ -15,7 +15,7 @@ permissions: {}
jobs:
release:
uses: hoverkraft-tech/ci-github-publish/.github/workflows/prepare-release.yml@b2562b46714e535a0113f90f554b55e1248212c1 # 0.26.3
uses: hoverkraft-tech/ci-github-publish/.github/workflows/prepare-release.yml@84d583ba7b357f9476707f54cf5419d630ae0145 # 0.26.2
permissions:
contents: read
pull-requests: write

View File

@ -18,7 +18,6 @@ jobs:
actions: read
contents: read
id-token: write
issues: write
packages: read
pull-requests: write
security-events: write

View File

@ -11,7 +11,7 @@ permissions: {}
jobs:
main:
uses: hoverkraft-tech/ci-github-common/.github/workflows/semantic-pull-request.yml@624be17604ee0a7378488191aacb35851e7cf001 # 0.37.1
uses: hoverkraft-tech/ci-github-common/.github/workflows/semantic-pull-request.yml@4bb7594b1bf3696c54b2bbae970376056853f8ea # 0.36.0
permissions:
contents: write
pull-requests: write

View File

@ -8,7 +8,7 @@ permissions: {}
jobs:
main:
uses: hoverkraft-tech/ci-github-common/.github/workflows/stale.yml@624be17604ee0a7378488191aacb35851e7cf001 # 0.37.1
uses: hoverkraft-tech/ci-github-common/.github/workflows/stale.yml@4bb7594b1bf3696c54b2bbae970376056853f8ea # 0.36.0
permissions:
issues: write
pull-requests: write

View File

@ -50,7 +50,7 @@ Some extra options can be passed to the `docker compose down` command using the
## Usage
```yaml
- uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0
- uses: hoverkraft-tech/compose-action@d2bee4f07e8ca410d6b196d00f90c12e7d48c33a # v2.6.0
with:
# Additional options to pass to `docker` command.
docker-flags: ""
@ -140,7 +140,7 @@ jobs:
- uses: actions/checkout@v4.2.2
- name: Run docker compose
uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0
uses: hoverkraft-tech/compose-action@d2bee4f07e8ca410d6b196d00f90c12e7d48c33a # v2.6.0
with:
compose-file: "./docker/docker-compose.yml"
@ -154,7 +154,7 @@ jobs:
```yaml
steps:
- uses: actions/checkout@v4.2.2
- uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0
- uses: hoverkraft-tech/compose-action@d2bee4f07e8ca410d6b196d00f90c12e7d48c33a # v2.6.0
with:
compose-file: "./docker/docker-compose.yml"
env:
@ -169,7 +169,7 @@ Perform `docker compose up` to some given service instead of all of them
steps:
# need checkout before using compose-action
- uses: actions/checkout@v3
- uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0
- uses: hoverkraft-tech/compose-action@d2bee4f07e8ca410d6b196d00f90c12e7d48c33a # v2.6.0
with:
compose-file: "./docker/docker-compose.yml"
services: |
@ -207,7 +207,7 @@ A full list of flags can be found in the [Docker compose documentation](https://
steps:
# need checkout before using compose-action
- uses: actions/checkout@v3
- uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0
- uses: hoverkraft-tech/compose-action@d2bee4f07e8ca410d6b196d00f90c12e7d48c33a # v2.6.0
with:
compose-file: "./docker/docker-compose.yml"
compose-flags: "--profile profile-1"
@ -221,7 +221,7 @@ This is useful when you have a base compose file and additional files for differ
steps:
# need checkout before using compose-action
- uses: actions/checkout@v3
- uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0
- uses: hoverkraft-tech/compose-action@d2bee4f07e8ca410d6b196d00f90c12e7d48c33a # v2.6.0
with:
compose-file: |
./docker/docker-compose.yml

379
dist/index.js generated vendored
View File

@ -8451,6 +8451,8 @@ function defaultFactory (origin, opts) {
class Agent extends DispatcherBase {
constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
super()
if (typeof factory !== 'function') {
throw new InvalidArgumentError('factory must be a function.')
}
@ -8463,8 +8465,6 @@ class Agent extends DispatcherBase {
throw new InvalidArgumentError('maxRedirections must be a positive number')
}
super(options)
if (connect && typeof connect !== 'function') {
connect = { ...connect }
}
@ -8836,9 +8836,6 @@ const EMPTY_BUF = Buffer.alloc(0)
const FastBuffer = Buffer[Symbol.species]
const addListener = util.addListener
const removeAllListeners = util.removeAllListeners
const kIdleSocketValidation = Symbol('kIdleSocketValidation')
const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout')
const kSocketUsed = Symbol('kSocketUsed')
let extractBody
@ -9061,60 +9058,15 @@ class Parser {
const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr
if (ret !== constants.ERROR.OK) {
const body = data.subarray(offset)
if (ret === constants.ERROR.PAUSED_UPGRADE) {
this.onUpgrade(body)
this.onUpgrade(data.slice(offset))
} else if (ret === constants.ERROR.PAUSED) {
this.paused = true
socket.unshift(body)
} else {
throw this.createError(ret, body)
}
}
} catch (err) {
util.destroy(socket, err)
}
}
finish () {
assert(currentParser === null)
assert(this.ptr != null)
assert(!this.paused)
const { llhttp } = this
let ret
try {
currentParser = this
ret = llhttp.llhttp_finish(this.ptr)
} finally {
currentParser = null
}
if (ret === constants.ERROR.OK) {
return null
}
if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) {
this.paused = true
return null
}
return this.createError(ret, EMPTY_BUF)
}
createError (ret, data) {
const { llhttp, contentLength, bytesRead } = this
if (contentLength && bytesRead !== parseInt(contentLength, 10)) {
return new ResponseContentLengthMismatchError()
}
socket.unshift(data.slice(offset))
} else if (ret !== constants.ERROR.OK) {
const ptr = llhttp.llhttp_get_error_reason(this.ptr)
let message = ''
/* istanbul ignore else: difficult to make a test case for */
if (ptr) {
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
message =
@ -9122,8 +9074,11 @@ class Parser {
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
')'
}
return new HTTPParserError(message, constants.ERROR[ret], data)
throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset))
}
} catch (err) {
util.destroy(socket, err)
}
}
destroy () {
@ -9153,11 +9108,6 @@ class Parser {
return -1
}
if (client[kRunning] === 0) {
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
return -1
}
const request = client[kQueue][client[kRunningIdx]]
if (!request) {
return -1
@ -9261,11 +9211,6 @@ class Parser {
return -1
}
if (client[kRunning] === 0) {
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
return -1
}
const request = client[kQueue][client[kRunningIdx]]
/* istanbul ignore next: difficult to make a test case for */
@ -9439,7 +9384,6 @@ class Parser {
request.onComplete(headers)
client[kQueue][client[kRunningIdx]++] = null
socket[kSocketUsed] = true
if (socket[kWriting]) {
assert(client[kRunning] === 0)
@ -9498,9 +9442,6 @@ async function connectH1 (client, socket) {
socket[kWriting] = false
socket[kReset] = false
socket[kBlocking] = false
socket[kIdleSocketValidation] = 0
socket[kIdleSocketValidationTimeout] = null
socket[kSocketUsed] = false
socket[kParser] = new Parser(client, socket, llhttpInstance)
addListener(socket, 'error', function (err) {
@ -9511,11 +9452,8 @@ async function connectH1 (client, socket) {
// On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
// to the user.
if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
const parserErr = parser.finish()
if (parserErr) {
this[kError] = parserErr
this[kClient][kOnError](parserErr)
}
// We treat all incoming data so for as a valid response.
parser.onMessageComplete()
return
}
@ -9534,10 +9472,8 @@ async function connectH1 (client, socket) {
const parser = this[kParser]
if (parser.statusCode && !parser.shouldKeepAlive) {
const parserErr = parser.finish()
if (parserErr) {
util.destroy(this, parserErr)
}
// We treat all incoming data so far as a valid response.
parser.onMessageComplete()
return
}
@ -9547,11 +9483,10 @@ async function connectH1 (client, socket) {
const client = this[kClient]
const parser = this[kParser]
clearIdleSocketValidation(this)
if (parser) {
if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
this[kError] = parser.finish() || this[kError]
// We treat all incoming data so far as a valid response.
parser.onMessageComplete()
}
this[kParser].destroy()
@ -9614,7 +9549,7 @@ async function connectH1 (client, socket) {
return socket.destroyed
},
busy (request) {
if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) {
if (socket[kWriting] || socket[kReset] || socket[kBlocking]) {
return true
}
@ -9652,31 +9587,6 @@ async function connectH1 (client, socket) {
}
}
function clearIdleSocketValidation (socket) {
if (socket[kIdleSocketValidationTimeout]) {
clearTimeout(socket[kIdleSocketValidationTimeout])
socket[kIdleSocketValidationTimeout] = null
}
socket[kIdleSocketValidation] = 0
}
function scheduleIdleSocketValidation (client, socket) {
socket[kIdleSocketValidation] = 1
socket[kIdleSocketValidationTimeout] = setTimeout(() => {
socket[kIdleSocketValidationTimeout] = null
socket[kIdleSocketValidation] = 2
if (client[kSocket] === socket && !socket.destroyed) {
client[kResume]()
}
}, 0)
socket[kIdleSocketValidationTimeout].unref?.()
}
/**
* @param {import('./client.js')} client
*/
function resumeH1 (client) {
const socket = client[kSocket]
@ -9691,32 +9601,6 @@ function resumeH1 (client) {
socket[kNoRef] = false
}
if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) {
if (socket[kIdleSocketValidation] === 0) {
scheduleIdleSocketValidation(client, socket)
socket[kParser].readMore()
if (socket.destroyed) {
return
}
return
}
if (socket[kIdleSocketValidation] === 1) {
socket[kParser].readMore()
if (socket.destroyed) {
return
}
return
}
}
if (client[kRunning] === 0) {
socket[kParser].readMore()
if (socket.destroyed) {
return
}
}
if (client[kSize] === 0) {
if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE)
@ -9810,7 +9694,6 @@ function writeH1 (client, request) {
}
const socket = client[kSocket]
clearIdleSocketValidation(socket)
const abort = (err) => {
if (request.aborted || request.completed) {
@ -11130,10 +11013,9 @@ class Client extends DispatcherBase {
autoSelectFamilyAttemptTimeout,
// h2
maxConcurrentStreams,
allowH2,
webSocket
allowH2
} = {}) {
super({ webSocket })
super()
if (keepAlive !== undefined) {
throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead')
@ -11665,24 +11547,15 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = __nc
const kOnDestroyed = Symbol('onDestroyed')
const kOnClosed = Symbol('onClosed')
const kInterceptedDispatch = Symbol('Intercepted Dispatch')
const kWebSocketOptions = Symbol('webSocketOptions')
class DispatcherBase extends Dispatcher {
constructor (opts) {
constructor () {
super()
this[kDestroyed] = false
this[kOnDestroyed] = null
this[kClosed] = false
this[kOnClosed] = []
this[kWebSocketOptions] = opts?.webSocket ?? {}
}
get webSocketOptions () {
return {
maxFragments: this[kWebSocketOptions].maxFragments ?? 131072,
maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024
}
}
get destroyed () {
@ -12242,8 +12115,8 @@ const kRemoveClient = Symbol('remove client')
const kStats = Symbol('stats')
class PoolBase extends DispatcherBase {
constructor (opts) {
super(opts)
constructor () {
super()
this[kQueue] = new FixedQueue()
this[kClients] = []
@ -12502,6 +12375,8 @@ class Pool extends PoolBase {
allowH2,
...options
} = {}) {
super()
if (connections != null && (!Number.isFinite(connections) || connections < 0)) {
throw new InvalidArgumentError('invalid connections')
}
@ -12526,8 +12401,6 @@ class Pool extends PoolBase {
})
}
super(options)
this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool)
? options.interceptors.Pool
: []
@ -17580,25 +17453,32 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
// If the attribute-name case-insensitively matches the string
// "SameSite", the user agent MUST process the cookie-av as follows:
const attributeValueLowercase = attributeValue.toLowerCase()
// 1. Let enforcement be "Default".
let enforcement = 'Default'
// 1. If cookie-av's attribute-value is a case-insensitive match for
// "None", append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of "None".
if (attributeValueLowercase === 'none') {
cookieAttributeList.sameSite = 'None'
} else if (attributeValueLowercase === 'strict') {
const attributeValueLowercase = attributeValue.toLowerCase()
// 2. If cookie-av's attribute-value is a case-insensitive match for
// "Strict", append an attribute to the cookie-attribute-list with
// an attribute-name of "SameSite" and an attribute-value of
// "Strict".
cookieAttributeList.sameSite = 'Strict'
} else if (attributeValueLowercase === 'lax') {
// 3. If cookie-av's attribute-value is a case-insensitive match for
// "Lax", append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of "Lax".
cookieAttributeList.sameSite = 'Lax'
// "None", set enforcement to "None".
if (attributeValueLowercase.includes('none')) {
enforcement = 'None'
}
// 3. If cookie-av's attribute-value is a case-insensitive match for
// "Strict", set enforcement to "Strict".
if (attributeValueLowercase.includes('strict')) {
enforcement = 'Strict'
}
// 4. If cookie-av's attribute-value is a case-insensitive match for
// "Lax", set enforcement to "Lax".
if (attributeValueLowercase.includes('lax')) {
enforcement = 'Lax'
}
// 5. Append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of
// enforcement.
cookieAttributeList.sameSite = enforcement
} else {
cookieAttributeList.unparsed ??= []
@ -30275,35 +30155,40 @@ 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 = {}
#maxPayloadSize = 0
/** @type {boolean} */
#aborted = false
/** @type {Function|null} */
#currentCallback = null
/**
* @param {Map<string, string>} extensions
*/
constructor (extensions, options) {
constructor (extensions) {
this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover')
this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits')
this.#maxPayloadSize = options.maxPayloadSize
}
/**
* Decompress a compressed payload.
* @param {Buffer} chunk Compressed data
* @param {boolean} fin Final fragment flag
* @param {Function} callback Callback function
*/
decompress (chunk, fin, callback) {
// An endpoint uses the following algorithm to decompress a message.
// 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the
// 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
@ -30326,12 +30211,23 @@ class PerMessageDeflate {
this.#inflate[kLength] = 0
this.#inflate.on('data', (data) => {
if (this.#aborted) {
return
}
this.#inflate[kLength] += data.length
if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
callback(new MessageSizeExceededError())
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
}
@ -30344,13 +30240,14 @@ class PerMessageDeflate {
})
}
this.#currentCallback = callback
this.#inflate.write(chunk)
if (fin) {
this.#inflate.write(tail)
}
this.#inflate.flush(() => {
if (!this.#inflate) {
if (this.#aborted || !this.#inflate) {
return
}
@ -30358,6 +30255,7 @@ class PerMessageDeflate {
this.#inflate[kBuffer].length = 0
this.#inflate[kLength] = 0
this.#currentCallback = null
callback(null, full)
})
@ -30392,12 +30290,6 @@ const {
const { WebsocketFrameSend } = __nccwpck_require__(3264)
const { closeWebSocketConnection } = __nccwpck_require__(6897)
const { PerMessageDeflate } = __nccwpck_require__(9469)
const { MessageSizeExceededError } = __nccwpck_require__(8707)
function failWebsocketConnectionWithCode (ws, code, reason) {
closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason))
failWebsocketConnection(ws, reason)
}
// This code was influenced by ws released under the MIT license.
// Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
@ -30406,7 +30298,6 @@ function failWebsocketConnectionWithCode (ws, code, reason) {
class ByteParser extends Writable {
#buffers = []
#fragmentsBytes = 0
#byteOffset = 0
#loop = false
@ -30418,27 +30309,18 @@ class ByteParser extends Writable {
/** @type {Map<string, PerMessageDeflate>} */
#extensions
/** @type {number} */
#maxFragments
/** @type {number} */
#maxPayloadSize
/**
* @param {import('./websocket').WebSocket} ws
* @param {Map<string, string>|null} extensions
* @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
*/
constructor (ws, extensions, options = {}) {
constructor (ws, extensions) {
super()
this.ws = ws
this.#extensions = extensions == null ? new Map() : extensions
this.#maxFragments = options.maxFragments ?? 0
this.#maxPayloadSize = options.maxPayloadSize ?? 0
if (this.#extensions.has('permessage-deflate')) {
this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions, options))
this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions))
}
}
@ -30454,19 +30336,6 @@ class ByteParser extends Writable {
this.run(callback)
}
#validatePayloadLength () {
if (
this.#maxPayloadSize > 0 &&
!isControlFrame(this.#info.opcode) &&
this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize
) {
failWebsocketConnectionWithCode(this.ws, 1009, 'Payload size exceeds maximum allowed size')
return false
}
return true
}
/**
* Runs whenever a new chunk is received.
* Callback is called whenever there are no more chunks buffering,
@ -30555,10 +30424,6 @@ class ByteParser extends Writable {
if (payloadLength <= 125) {
this.#info.payloadLength = payloadLength
this.#state = parserStates.READ_DATA
if (!this.#validatePayloadLength()) {
return
}
} else if (payloadLength === 126) {
this.#state = parserStates.PAYLOADLENGTH_16
} else if (payloadLength === 127) {
@ -30583,10 +30448,6 @@ class ByteParser extends Writable {
this.#info.payloadLength = buffer.readUInt16BE(0)
this.#state = parserStates.READ_DATA
if (!this.#validatePayloadLength()) {
return
}
} else if (this.#state === parserStates.PAYLOADLENGTH_64) {
if (this.#byteOffset < 8) {
return callback()
@ -30609,10 +30470,6 @@ class ByteParser extends Writable {
this.#info.payloadLength = lower
this.#state = parserStates.READ_DATA
if (!this.#validatePayloadLength()) {
return
}
} else if (this.#state === parserStates.READ_DATA) {
if (this.#byteOffset < this.#info.payloadLength) {
return callback()
@ -30625,43 +30482,27 @@ class ByteParser extends Writable {
this.#state = parserStates.INFO
} else {
if (!this.#info.compressed) {
if (!this.writeFragments(body)) {
return
}
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
return
}
this.#fragments.push(body)
// If the frame is not fragmented, a message has been received.
// If the frame is fragmented, it will terminate with a fin bit set
// and an opcode of 0 (continuation), therefore we handle that when
// parsing continuation frames, not here.
if (!this.#info.fragmented && this.#info.fin) {
websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments())
const fullMessage = Buffer.concat(this.#fragments)
websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage)
this.#fragments.length = 0
}
this.#state = parserStates.INFO
} else {
this.#extensions.get('permessage-deflate').decompress(
body,
this.#info.fin,
(error, data) => {
this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => {
if (error) {
const code = error instanceof MessageSizeExceededError ? 1009 : 1007
failWebsocketConnectionWithCode(this.ws, code, error.message)
failWebsocketConnection(this.ws, error.message)
return
}
if (!this.writeFragments(data)) {
return
}
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
return
}
this.#fragments.push(data)
if (!this.#info.fin) {
this.#state = parserStates.INFO
@ -30670,13 +30511,13 @@ class ByteParser extends Writable {
return
}
websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments())
websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments))
this.#loop = true
this.#state = parserStates.INFO
this.#fragments.length = 0
this.run(callback)
}
)
})
this.#loop = false
break
@ -30728,35 +30569,6 @@ class ByteParser extends Writable {
return buffer
}
writeFragments (fragment) {
if (
this.#maxFragments > 0 &&
this.#fragments.length === this.#maxFragments
) {
failWebsocketConnectionWithCode(this.ws, 1008, 'Too many message fragments')
return false
}
this.#fragmentsBytes += fragment.length
this.#fragments.push(fragment)
return true
}
consumeFragments () {
const fragments = this.#fragments
if (fragments.length === 1) {
this.#fragmentsBytes = 0
return fragments.shift()
}
const output = Buffer.concat(fragments, this.#fragmentsBytes)
this.#fragments = []
this.#fragmentsBytes = 0
return output
}
parseCloseBody (data) {
assert(data.length !== 1)
@ -31788,14 +31600,7 @@ class WebSocket extends EventTarget {
// once this happens, the connection is open
this[kResponse] = response
const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions
const maxFragments = webSocketOptions?.maxFragments
const maxPayloadSize = webSocketOptions?.maxPayloadSize
const parser = new ByteParser(this, parsedExtensions, {
maxFragments,
maxPayloadSize
})
const parser = new ByteParser(this, parsedExtensions)
parser.on('drain', onParserDrain)
parser.on('error', onParserError.bind(this))

379
dist/post.js generated vendored
View File

@ -4940,6 +4940,8 @@ function defaultFactory (origin, opts) {
class Agent extends DispatcherBase {
constructor ({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) {
super()
if (typeof factory !== 'function') {
throw new InvalidArgumentError('factory must be a function.')
}
@ -4952,8 +4954,6 @@ class Agent extends DispatcherBase {
throw new InvalidArgumentError('maxRedirections must be a positive number')
}
super(options)
if (connect && typeof connect !== 'function') {
connect = { ...connect }
}
@ -5325,9 +5325,6 @@ const EMPTY_BUF = Buffer.alloc(0)
const FastBuffer = Buffer[Symbol.species]
const addListener = util.addListener
const removeAllListeners = util.removeAllListeners
const kIdleSocketValidation = Symbol('kIdleSocketValidation')
const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout')
const kSocketUsed = Symbol('kSocketUsed')
let extractBody
@ -5550,60 +5547,15 @@ class Parser {
const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr
if (ret !== constants.ERROR.OK) {
const body = data.subarray(offset)
if (ret === constants.ERROR.PAUSED_UPGRADE) {
this.onUpgrade(body)
this.onUpgrade(data.slice(offset))
} else if (ret === constants.ERROR.PAUSED) {
this.paused = true
socket.unshift(body)
} else {
throw this.createError(ret, body)
}
}
} catch (err) {
util.destroy(socket, err)
}
}
finish () {
assert(currentParser === null)
assert(this.ptr != null)
assert(!this.paused)
const { llhttp } = this
let ret
try {
currentParser = this
ret = llhttp.llhttp_finish(this.ptr)
} finally {
currentParser = null
}
if (ret === constants.ERROR.OK) {
return null
}
if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) {
this.paused = true
return null
}
return this.createError(ret, EMPTY_BUF)
}
createError (ret, data) {
const { llhttp, contentLength, bytesRead } = this
if (contentLength && bytesRead !== parseInt(contentLength, 10)) {
return new ResponseContentLengthMismatchError()
}
socket.unshift(data.slice(offset))
} else if (ret !== constants.ERROR.OK) {
const ptr = llhttp.llhttp_get_error_reason(this.ptr)
let message = ''
/* istanbul ignore else: difficult to make a test case for */
if (ptr) {
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
message =
@ -5611,8 +5563,11 @@ class Parser {
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
')'
}
return new HTTPParserError(message, constants.ERROR[ret], data)
throw new HTTPParserError(message, constants.ERROR[ret], data.slice(offset))
}
} catch (err) {
util.destroy(socket, err)
}
}
destroy () {
@ -5642,11 +5597,6 @@ class Parser {
return -1
}
if (client[kRunning] === 0) {
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
return -1
}
const request = client[kQueue][client[kRunningIdx]]
if (!request) {
return -1
@ -5750,11 +5700,6 @@ class Parser {
return -1
}
if (client[kRunning] === 0) {
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
return -1
}
const request = client[kQueue][client[kRunningIdx]]
/* istanbul ignore next: difficult to make a test case for */
@ -5928,7 +5873,6 @@ class Parser {
request.onComplete(headers)
client[kQueue][client[kRunningIdx]++] = null
socket[kSocketUsed] = true
if (socket[kWriting]) {
assert(client[kRunning] === 0)
@ -5987,9 +5931,6 @@ async function connectH1 (client, socket) {
socket[kWriting] = false
socket[kReset] = false
socket[kBlocking] = false
socket[kIdleSocketValidation] = 0
socket[kIdleSocketValidationTimeout] = null
socket[kSocketUsed] = false
socket[kParser] = new Parser(client, socket, llhttpInstance)
addListener(socket, 'error', function (err) {
@ -6000,11 +5941,8 @@ async function connectH1 (client, socket) {
// On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
// to the user.
if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
const parserErr = parser.finish()
if (parserErr) {
this[kError] = parserErr
this[kClient][kOnError](parserErr)
}
// We treat all incoming data so for as a valid response.
parser.onMessageComplete()
return
}
@ -6023,10 +5961,8 @@ async function connectH1 (client, socket) {
const parser = this[kParser]
if (parser.statusCode && !parser.shouldKeepAlive) {
const parserErr = parser.finish()
if (parserErr) {
util.destroy(this, parserErr)
}
// We treat all incoming data so far as a valid response.
parser.onMessageComplete()
return
}
@ -6036,11 +5972,10 @@ async function connectH1 (client, socket) {
const client = this[kClient]
const parser = this[kParser]
clearIdleSocketValidation(this)
if (parser) {
if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
this[kError] = parser.finish() || this[kError]
// We treat all incoming data so far as a valid response.
parser.onMessageComplete()
}
this[kParser].destroy()
@ -6103,7 +6038,7 @@ async function connectH1 (client, socket) {
return socket.destroyed
},
busy (request) {
if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) {
if (socket[kWriting] || socket[kReset] || socket[kBlocking]) {
return true
}
@ -6141,31 +6076,6 @@ async function connectH1 (client, socket) {
}
}
function clearIdleSocketValidation (socket) {
if (socket[kIdleSocketValidationTimeout]) {
clearTimeout(socket[kIdleSocketValidationTimeout])
socket[kIdleSocketValidationTimeout] = null
}
socket[kIdleSocketValidation] = 0
}
function scheduleIdleSocketValidation (client, socket) {
socket[kIdleSocketValidation] = 1
socket[kIdleSocketValidationTimeout] = setTimeout(() => {
socket[kIdleSocketValidationTimeout] = null
socket[kIdleSocketValidation] = 2
if (client[kSocket] === socket && !socket.destroyed) {
client[kResume]()
}
}, 0)
socket[kIdleSocketValidationTimeout].unref?.()
}
/**
* @param {import('./client.js')} client
*/
function resumeH1 (client) {
const socket = client[kSocket]
@ -6180,32 +6090,6 @@ function resumeH1 (client) {
socket[kNoRef] = false
}
if (client[kRunning] === 0 && client[kPending] > 0 && socket[kSocketUsed]) {
if (socket[kIdleSocketValidation] === 0) {
scheduleIdleSocketValidation(client, socket)
socket[kParser].readMore()
if (socket.destroyed) {
return
}
return
}
if (socket[kIdleSocketValidation] === 1) {
socket[kParser].readMore()
if (socket.destroyed) {
return
}
return
}
}
if (client[kRunning] === 0) {
socket[kParser].readMore()
if (socket.destroyed) {
return
}
}
if (client[kSize] === 0) {
if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE)
@ -6299,7 +6183,6 @@ function writeH1 (client, request) {
}
const socket = client[kSocket]
clearIdleSocketValidation(socket)
const abort = (err) => {
if (request.aborted || request.completed) {
@ -7619,10 +7502,9 @@ class Client extends DispatcherBase {
autoSelectFamilyAttemptTimeout,
// h2
maxConcurrentStreams,
allowH2,
webSocket
allowH2
} = {}) {
super({ webSocket })
super()
if (keepAlive !== undefined) {
throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead')
@ -8154,24 +8036,15 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = __nc
const kOnDestroyed = Symbol('onDestroyed')
const kOnClosed = Symbol('onClosed')
const kInterceptedDispatch = Symbol('Intercepted Dispatch')
const kWebSocketOptions = Symbol('webSocketOptions')
class DispatcherBase extends Dispatcher {
constructor (opts) {
constructor () {
super()
this[kDestroyed] = false
this[kOnDestroyed] = null
this[kClosed] = false
this[kOnClosed] = []
this[kWebSocketOptions] = opts?.webSocket ?? {}
}
get webSocketOptions () {
return {
maxFragments: this[kWebSocketOptions].maxFragments ?? 131072,
maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024
}
}
get destroyed () {
@ -8731,8 +8604,8 @@ const kRemoveClient = Symbol('remove client')
const kStats = Symbol('stats')
class PoolBase extends DispatcherBase {
constructor (opts) {
super(opts)
constructor () {
super()
this[kQueue] = new FixedQueue()
this[kClients] = []
@ -8991,6 +8864,8 @@ class Pool extends PoolBase {
allowH2,
...options
} = {}) {
super()
if (connections != null && (!Number.isFinite(connections) || connections < 0)) {
throw new InvalidArgumentError('invalid connections')
}
@ -9015,8 +8890,6 @@ class Pool extends PoolBase {
})
}
super(options)
this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool)
? options.interceptors.Pool
: []
@ -14069,25 +13942,32 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
// If the attribute-name case-insensitively matches the string
// "SameSite", the user agent MUST process the cookie-av as follows:
const attributeValueLowercase = attributeValue.toLowerCase()
// 1. Let enforcement be "Default".
let enforcement = 'Default'
// 1. If cookie-av's attribute-value is a case-insensitive match for
// "None", append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of "None".
if (attributeValueLowercase === 'none') {
cookieAttributeList.sameSite = 'None'
} else if (attributeValueLowercase === 'strict') {
const attributeValueLowercase = attributeValue.toLowerCase()
// 2. If cookie-av's attribute-value is a case-insensitive match for
// "Strict", append an attribute to the cookie-attribute-list with
// an attribute-name of "SameSite" and an attribute-value of
// "Strict".
cookieAttributeList.sameSite = 'Strict'
} else if (attributeValueLowercase === 'lax') {
// 3. If cookie-av's attribute-value is a case-insensitive match for
// "Lax", append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of "Lax".
cookieAttributeList.sameSite = 'Lax'
// "None", set enforcement to "None".
if (attributeValueLowercase.includes('none')) {
enforcement = 'None'
}
// 3. If cookie-av's attribute-value is a case-insensitive match for
// "Strict", set enforcement to "Strict".
if (attributeValueLowercase.includes('strict')) {
enforcement = 'Strict'
}
// 4. If cookie-av's attribute-value is a case-insensitive match for
// "Lax", set enforcement to "Lax".
if (attributeValueLowercase.includes('lax')) {
enforcement = 'Lax'
}
// 5. Append an attribute to the cookie-attribute-list with an
// attribute-name of "SameSite" and an attribute-value of
// enforcement.
cookieAttributeList.sameSite = enforcement
} else {
cookieAttributeList.unparsed ??= []
@ -26764,35 +26644,40 @@ 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 = {}
#maxPayloadSize = 0
/** @type {boolean} */
#aborted = false
/** @type {Function|null} */
#currentCallback = null
/**
* @param {Map<string, string>} extensions
*/
constructor (extensions, options) {
constructor (extensions) {
this.#options.serverNoContextTakeover = extensions.has('server_no_context_takeover')
this.#options.serverMaxWindowBits = extensions.get('server_max_window_bits')
this.#maxPayloadSize = options.maxPayloadSize
}
/**
* Decompress a compressed payload.
* @param {Buffer} chunk Compressed data
* @param {boolean} fin Final fragment flag
* @param {Function} callback Callback function
*/
decompress (chunk, fin, callback) {
// An endpoint uses the following algorithm to decompress a message.
// 1. Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the
// 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
@ -26815,12 +26700,23 @@ class PerMessageDeflate {
this.#inflate[kLength] = 0
this.#inflate.on('data', (data) => {
if (this.#aborted) {
return
}
this.#inflate[kLength] += data.length
if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
callback(new MessageSizeExceededError())
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
}
@ -26833,13 +26729,14 @@ class PerMessageDeflate {
})
}
this.#currentCallback = callback
this.#inflate.write(chunk)
if (fin) {
this.#inflate.write(tail)
}
this.#inflate.flush(() => {
if (!this.#inflate) {
if (this.#aborted || !this.#inflate) {
return
}
@ -26847,6 +26744,7 @@ class PerMessageDeflate {
this.#inflate[kBuffer].length = 0
this.#inflate[kLength] = 0
this.#currentCallback = null
callback(null, full)
})
@ -26881,12 +26779,6 @@ const {
const { WebsocketFrameSend } = __nccwpck_require__(3264)
const { closeWebSocketConnection } = __nccwpck_require__(6897)
const { PerMessageDeflate } = __nccwpck_require__(9469)
const { MessageSizeExceededError } = __nccwpck_require__(8707)
function failWebsocketConnectionWithCode (ws, code, reason) {
closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason))
failWebsocketConnection(ws, reason)
}
// This code was influenced by ws released under the MIT license.
// Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
@ -26895,7 +26787,6 @@ function failWebsocketConnectionWithCode (ws, code, reason) {
class ByteParser extends Writable {
#buffers = []
#fragmentsBytes = 0
#byteOffset = 0
#loop = false
@ -26907,27 +26798,18 @@ class ByteParser extends Writable {
/** @type {Map<string, PerMessageDeflate>} */
#extensions
/** @type {number} */
#maxFragments
/** @type {number} */
#maxPayloadSize
/**
* @param {import('./websocket').WebSocket} ws
* @param {Map<string, string>|null} extensions
* @param {{ maxFragments?: number, maxPayloadSize?: number }} [options]
*/
constructor (ws, extensions, options = {}) {
constructor (ws, extensions) {
super()
this.ws = ws
this.#extensions = extensions == null ? new Map() : extensions
this.#maxFragments = options.maxFragments ?? 0
this.#maxPayloadSize = options.maxPayloadSize ?? 0
if (this.#extensions.has('permessage-deflate')) {
this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions, options))
this.#extensions.set('permessage-deflate', new PerMessageDeflate(extensions))
}
}
@ -26943,19 +26825,6 @@ class ByteParser extends Writable {
this.run(callback)
}
#validatePayloadLength () {
if (
this.#maxPayloadSize > 0 &&
!isControlFrame(this.#info.opcode) &&
this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize
) {
failWebsocketConnectionWithCode(this.ws, 1009, 'Payload size exceeds maximum allowed size')
return false
}
return true
}
/**
* Runs whenever a new chunk is received.
* Callback is called whenever there are no more chunks buffering,
@ -27044,10 +26913,6 @@ class ByteParser extends Writable {
if (payloadLength <= 125) {
this.#info.payloadLength = payloadLength
this.#state = parserStates.READ_DATA
if (!this.#validatePayloadLength()) {
return
}
} else if (payloadLength === 126) {
this.#state = parserStates.PAYLOADLENGTH_16
} else if (payloadLength === 127) {
@ -27072,10 +26937,6 @@ class ByteParser extends Writable {
this.#info.payloadLength = buffer.readUInt16BE(0)
this.#state = parserStates.READ_DATA
if (!this.#validatePayloadLength()) {
return
}
} else if (this.#state === parserStates.PAYLOADLENGTH_64) {
if (this.#byteOffset < 8) {
return callback()
@ -27098,10 +26959,6 @@ class ByteParser extends Writable {
this.#info.payloadLength = lower
this.#state = parserStates.READ_DATA
if (!this.#validatePayloadLength()) {
return
}
} else if (this.#state === parserStates.READ_DATA) {
if (this.#byteOffset < this.#info.payloadLength) {
return callback()
@ -27114,43 +26971,27 @@ class ByteParser extends Writable {
this.#state = parserStates.INFO
} else {
if (!this.#info.compressed) {
if (!this.writeFragments(body)) {
return
}
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
return
}
this.#fragments.push(body)
// If the frame is not fragmented, a message has been received.
// If the frame is fragmented, it will terminate with a fin bit set
// and an opcode of 0 (continuation), therefore we handle that when
// parsing continuation frames, not here.
if (!this.#info.fragmented && this.#info.fin) {
websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments())
const fullMessage = Buffer.concat(this.#fragments)
websocketMessageReceived(this.ws, this.#info.binaryType, fullMessage)
this.#fragments.length = 0
}
this.#state = parserStates.INFO
} else {
this.#extensions.get('permessage-deflate').decompress(
body,
this.#info.fin,
(error, data) => {
this.#extensions.get('permessage-deflate').decompress(body, this.#info.fin, (error, data) => {
if (error) {
const code = error instanceof MessageSizeExceededError ? 1009 : 1007
failWebsocketConnectionWithCode(this.ws, code, error.message)
failWebsocketConnection(this.ws, error.message)
return
}
if (!this.writeFragments(data)) {
return
}
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message)
return
}
this.#fragments.push(data)
if (!this.#info.fin) {
this.#state = parserStates.INFO
@ -27159,13 +27000,13 @@ class ByteParser extends Writable {
return
}
websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments())
websocketMessageReceived(this.ws, this.#info.binaryType, Buffer.concat(this.#fragments))
this.#loop = true
this.#state = parserStates.INFO
this.#fragments.length = 0
this.run(callback)
}
)
})
this.#loop = false
break
@ -27217,35 +27058,6 @@ class ByteParser extends Writable {
return buffer
}
writeFragments (fragment) {
if (
this.#maxFragments > 0 &&
this.#fragments.length === this.#maxFragments
) {
failWebsocketConnectionWithCode(this.ws, 1008, 'Too many message fragments')
return false
}
this.#fragmentsBytes += fragment.length
this.#fragments.push(fragment)
return true
}
consumeFragments () {
const fragments = this.#fragments
if (fragments.length === 1) {
this.#fragmentsBytes = 0
return fragments.shift()
}
const output = Buffer.concat(fragments, this.#fragmentsBytes)
this.#fragments = []
this.#fragmentsBytes = 0
return output
}
parseCloseBody (data) {
assert(data.length !== 1)
@ -28277,14 +28089,7 @@ class WebSocket extends EventTarget {
// once this happens, the connection is open
this[kResponse] = response
const webSocketOptions = this[kController]?.dispatcher?.webSocketOptions
const maxFragments = webSocketOptions?.maxFragments
const maxPayloadSize = webSocketOptions?.maxPayloadSize
const parser = new ByteParser(this, parsedExtensions, {
maxFragments,
maxPayloadSize
})
const parser = new ByteParser(this, parsedExtensions)
parser.on('drain', onParserDrain)
parser.on('error', onParserError.bind(this))

36
package-lock.json generated
View File

@ -17,7 +17,7 @@
},
"devDependencies": {
"@ts-dev-tools/core": "^1.12.4",
"@vercel/ncc": "^0.44.0"
"@vercel/ncc": "^0.38.4"
},
"engines": {
"node": ">=24"
@ -729,9 +729,9 @@
}
},
"node_modules/@octokit/action/node_modules/undici": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz",
"integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
"version": "7.24.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.24.2.tgz",
"integrity": "sha512-P9J1HWYV/ajFr8uCqk5QixwiRKmB1wOamgS0e+o2Z4A44Ej2+thFVRLG/eA7qprx88XXhnV5Bl8LHXTURpzB3Q==",
"license": "MIT",
"engines": {
"node": ">=20.18.1"
@ -1289,9 +1289,9 @@
}
},
"node_modules/@vercel/ncc": {
"version": "0.44.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.44.0.tgz",
"integrity": "sha512-pHyI+bZokSgIscTKFSmpNk5vZzmOrb9RW0Vu4SRyqUvkJ0kgg3PzaZLLDVTFXhbUiCqg0/Eu8L4fKtgViA92kg==",
"version": "0.38.4",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.4.tgz",
"integrity": "sha512-8LwjnlP39s08C08J5NstzriPvW1SP8Zfpp1BvC2sI35kPeZnHfxVkCwu4/+Wodgnd60UtT1n8K8zw+Mp7J9JmQ==",
"dev": true,
"license": "MIT",
"bin": {
@ -2010,20 +2010,10 @@
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@ -2750,9 +2740,9 @@
}
},
"node_modules/undici": {
"version": "6.27.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz",
"integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==",
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
"integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
"license": "MIT",
"engines": {
"node": ">=18.17"

View File

@ -33,7 +33,7 @@
},
"devDependencies": {
"@ts-dev-tools/core": "^1.12.4",
"@vercel/ncc": "^0.44.0"
"@vercel/ncc": "^0.38.4"
},
"scripts": {
"package": "npm run package:index && npm run package:post",