diff --git a/.github/actions/javascript/authorChecklist/index.js b/.github/actions/javascript/authorChecklist/index.js index b06a43adc37e..f76542955ddf 100644 --- a/.github/actions/javascript/authorChecklist/index.js +++ b/.github/actions/javascript/authorChecklist/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index 00e2f735fcb4..906a5fe20da8 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/bumpVersion/index.js b/.github/actions/javascript/bumpVersion/index.js index c2258fb0a82d..479e50a322da 100644 --- a/.github/actions/javascript/bumpVersion/index.js +++ b/.github/actions/javascript/bumpVersion/index.js @@ -2312,66 +2312,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -2438,11 +2382,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2454,9 +2394,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request.host !== null) { @@ -2566,21 +2503,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -6187,7 +6116,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -6234,9 +6162,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -6399,55 +6324,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6467,10 +6361,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { 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; @@ -6514,7 +6404,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6539,10 +6429,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request, error2); - util.destroy(socket, error2); + request.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6551,10 +6440,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { 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; @@ -6680,7 +6565,6 @@ var require_client_h1 = __commonJS({ } request.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6724,19 +6608,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6751,10 +6628,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6762,10 +6636,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6814,7 +6687,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request) { @@ -6832,23 +6705,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6861,29 +6717,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6914,16 +6747,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6944,18 +6769,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request.aborted) { + const abort = (err) => { + if (request.aborted || request.completed) { return; } - if (request.completed) { - if (request.upgrade || request.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } - return; - } - util.errorRequest(client, request, error2 || new RequestAbortedError()); + util.errorRequest(client, request, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -7311,7 +7129,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -7372,10 +7189,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7539,22 +7352,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request.aborted) { + const abort = (err) => { + if (request.aborted || request.completed) { return; } - if (request.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } - return; - } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7569,42 +7376,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request.onUpgradeError(error2); - }; - const onReady = () => { - try { - request.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -8165,10 +7948,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8674,8 +8456,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8846,6 +8628,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8866,7 +8649,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -9066,6 +8848,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -9075,7 +8858,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9516,24 +9298,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9587,7 +9351,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9597,17 +9360,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9669,9 +9421,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9720,21 +9470,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9742,7 +9480,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9750,11 +9487,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9774,7 +9506,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9802,7 +9533,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16601,48 +16332,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path2.length; ++i) { const code = path2.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16725,11 +16422,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16859,14 +16552,18 @@ var require_parse2 = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17688,7 +17385,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17794,26 +17491,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17832,12 +17534,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17847,17 +17557,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17888,14 +17600,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17903,21 +17609,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17932,13 +17635,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17998,9 +17694,6 @@ var require_receiver = __commonJS({ 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) { @@ -18021,9 +17714,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -18037,9 +17727,6 @@ var require_receiver = __commonJS({ } 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(); @@ -18050,46 +17737,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -18132,26 +17805,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -18363,6 +18016,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -18406,6 +18061,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18589,13 +18247,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18670,6 +18322,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18748,40 +18413,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18801,13 +18432,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18838,30 +18466,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18870,16 +18531,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18895,42 +18557,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18955,120 +18618,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/checkAndroidStatus/index.js b/.github/actions/javascript/checkAndroidStatus/index.js index de9e0e53ebc4..cf13138d08ce 100644 --- a/.github/actions/javascript/checkAndroidStatus/index.js +++ b/.github/actions/javascript/checkAndroidStatus/index.js @@ -1875,66 +1875,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -2001,11 +1945,7 @@ var require_request = __commonJS({ } else if (typeof val[i2] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i2]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i2]}`); } } val = arr; @@ -2017,9 +1957,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2129,21 +2066,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5750,7 +5679,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5797,9 +5725,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5962,55 +5887,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); - } + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6030,10 +5924,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6077,7 +5967,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6102,10 +5992,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6114,10 +6003,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6243,7 +6128,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6287,19 +6171,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6314,10 +6191,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6325,10 +6199,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6377,7 +6250,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6395,23 +6268,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6424,29 +6280,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6477,16 +6310,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6507,18 +6332,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6874,7 +6692,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline: pipeline2 } = __require("node:stream"); var util = require_util(); var { @@ -6935,10 +6752,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7102,22 +6915,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } - return; - } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7132,42 +6939,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7728,10 +7511,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8237,8 +8019,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8409,6 +8191,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8429,7 +8212,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8629,6 +8411,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8638,7 +8421,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9079,24 +8861,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9150,7 +8914,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9160,17 +8923,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9232,9 +8984,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9283,21 +9033,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9305,7 +9043,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9313,11 +9050,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9337,7 +9069,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9365,7 +9096,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16164,48 +15895,14 @@ var require_util6 = __commonJS({ for (let i2 = 0; i2 < path.length; ++i2) { const code = path.charCodeAt(i2); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i2 = 0; i2 < domain.length; ++i2) { - const code = domain.charCodeAt(i2); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i2 - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16288,11 +15985,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16422,14 +16115,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17251,7 +16948,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17357,26 +17054,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17395,12 +17097,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17410,17 +17120,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17451,14 +17163,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17466,21 +17172,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17495,13 +17198,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17561,9 +17257,6 @@ var require_receiver = __commonJS({ 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) { @@ -17584,9 +17277,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17600,9 +17290,6 @@ var require_receiver = __commonJS({ } this.#info.payloadLength = lower2; this.#state = parserStates.READ_DATA; - if (!this.#validatePayloadLength()) { - return; - } } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { return callback(); @@ -17613,46 +17300,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17695,26 +17368,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17926,6 +17579,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17969,6 +17624,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18152,13 +17810,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18233,6 +17885,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18311,40 +17976,6 @@ var require_eventsource_stream = __commonJS({ var CR2 = 13; var COLON2 = 58; var SPACE2 = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i2 = start; i2 < buffer.length; i2++) { - if (buffer[i2] < 48 || buffer[i2] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i2 = start; i2 < buffer.length; i2++) { - if (buffer[i2] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i2 = 0; i2 < length; i2++) { - if (line[i2] !== field[i2]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18364,13 +17995,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18401,30 +18029,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF2) { + if (this.buffer[this.pos] === LF2) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF2 || byte === CR2) { - if (byte === CR2) { + if (this.buffer[this.pos] === LF2 || this.buffer[this.pos] === CR2) { + if (this.buffer[this.pos] === CR2) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18433,16 +18094,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF2 || byte === CR2) { - if (byte === CR2) { + if (this.buffer[this.pos] === LF2 || this.buffer[this.pos] === CR2) { + if (this.buffer[this.pos] === CR2) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18458,42 +18120,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE2) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18518,120 +18181,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i2 = this.lineChunkIndex; i2 <= this.chunkIndex; i2++) { - const chunk = this.chunks[i2]; - const start = i2 === this.lineChunkIndex ? this.linePos : 0; - const end = i2 === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/checkDeployBlockers/index.js b/.github/actions/javascript/checkDeployBlockers/index.js index c59c854097c1..2ca391c52c00 100644 --- a/.github/actions/javascript/checkDeployBlockers/index.js +++ b/.github/actions/javascript/checkDeployBlockers/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/checkSVGCompression/index.js b/.github/actions/javascript/checkSVGCompression/index.js index cad1560febba..1bd2d9dfd701 100644 --- a/.github/actions/javascript/checkSVGCompression/index.js +++ b/.github/actions/javascript/checkSVGCompression/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path2.length; ++i) { const code = path2.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/failureNotifier/index.js b/.github/actions/javascript/failureNotifier/index.js index 208e6286e656..7eedc830062e 100644 --- a/.github/actions/javascript/failureNotifier/index.js +++ b/.github/actions/javascript/failureNotifier/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/formatCodeCovComment/index.js b/.github/actions/javascript/formatCodeCovComment/index.js index 9aac21e43b56..133b8de4b0d2 100644 --- a/.github/actions/javascript/formatCodeCovComment/index.js +++ b/.github/actions/javascript/formatCodeCovComment/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/generateHelpPreviewComment/index.js b/.github/actions/javascript/generateHelpPreviewComment/index.js index 222ea227535c..4fffa145a897 100644 --- a/.github/actions/javascript/generateHelpPreviewComment/index.js +++ b/.github/actions/javascript/generateHelpPreviewComment/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error) { - util.errorRequest(client, request2, error); - util.destroy(socket, error); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error = error || new RequestAbortedError(); - util.errorRequest(client, request2, error); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error); + util.destroy(stream, err); } - util.destroy(body, error); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error) { - stream.off("response", onResponse); - abort(error); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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) => { - if (error) { - const code = error instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error, data) => { + if (error) { + failWebsocketConnection(this.ws, error.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/getAndroidRolloutPercentage/index.js b/.github/actions/javascript/getAndroidRolloutPercentage/index.js index 1abd092e27ea..e970b3649819 100644 --- a/.github/actions/javascript/getAndroidRolloutPercentage/index.js +++ b/.github/actions/javascript/getAndroidRolloutPercentage/index.js @@ -1875,66 +1875,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -2001,11 +1945,7 @@ var require_request = __commonJS({ } else if (typeof val[i2] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i2]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i2]}`); } } val = arr; @@ -2017,9 +1957,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request.host !== null) { @@ -2129,21 +2066,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5750,7 +5679,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5797,9 +5725,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5962,55 +5887,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); - } + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6030,10 +5924,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { 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; @@ -6077,7 +5967,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6102,10 +5992,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request.onUpgrade(statusCode, headers, socket, statusText); - } catch (error) { - util.errorRequest(client, request, error); - util.destroy(socket, error); + request.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6114,10 +6003,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { 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; @@ -6243,7 +6128,6 @@ var require_client_h1 = __commonJS({ } request.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6287,19 +6171,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6314,10 +6191,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6325,10 +6199,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6377,7 +6250,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request) { @@ -6395,23 +6268,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6424,29 +6280,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6477,16 +6310,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6507,18 +6332,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error) => { - if (request.aborted) { - return; - } - if (request.completed) { - if (request.upgrade || request.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request.aborted || request.completed) { return; } - util.errorRequest(client, request, error || new RequestAbortedError()); + util.errorRequest(client, request, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6874,7 +6692,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline: pipeline2 } = __require("node:stream"); var util = require_util(); var { @@ -6935,10 +6752,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7102,22 +6915,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error) => { - if (request.aborted) { - return; - } - if (request.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error || new RequestAbortedError()); - } + const abort = (err) => { + if (request.aborted || request.completed) { return; } - error = error || new RequestAbortedError(); - util.errorRequest(client, request, error); + err = err || new RequestAbortedError(); + util.errorRequest(client, request, err); if (stream != null) { - util.destroy(stream, error); + util.destroy(stream, err); } - util.destroy(body, error); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7132,42 +6939,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request.onUpgradeError(error); - }; - const onReady = () => { - try { - request.onUpgrade(null, null, stream); - } catch (error) { - stream.off("response", onResponse); - abort(error); - return; - } - if (request.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7728,10 +7511,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8237,8 +8019,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8409,6 +8191,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8429,7 +8212,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8629,6 +8411,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8638,7 +8421,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9079,24 +8861,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9150,7 +8914,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9160,17 +8923,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9232,9 +8984,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9283,21 +9033,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9305,7 +9043,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9313,11 +9050,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9337,7 +9069,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9365,7 +9096,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16164,48 +15895,14 @@ var require_util6 = __commonJS({ for (let i2 = 0; i2 < path.length; ++i2) { const code = path.charCodeAt(i2); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i2 = 0; i2 < domain.length; ++i2) { - const code = domain.charCodeAt(i2); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i2 - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16288,11 +15985,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16422,14 +16115,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; + } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17251,7 +16948,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17357,26 +17054,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17395,12 +17097,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17410,17 +17120,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17451,14 +17163,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17466,21 +17172,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17495,13 +17198,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17561,9 +17257,6 @@ var require_receiver = __commonJS({ 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) { @@ -17584,9 +17277,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17600,9 +17290,6 @@ var require_receiver = __commonJS({ } this.#info.payloadLength = lower2; this.#state = parserStates.READ_DATA; - if (!this.#validatePayloadLength()) { - return; - } } else if (this.#state === parserStates.READ_DATA) { if (this.#byteOffset < this.#info.payloadLength) { return callback(); @@ -17613,46 +17300,32 @@ var require_receiver = __commonJS({ 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 (!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) => { - if (error) { - const code = error instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error, data) => { + if (error) { + failWebsocketConnection(this.ws, error.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17695,26 +17368,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17926,6 +17579,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17969,6 +17624,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18152,13 +17810,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18233,6 +17885,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18311,40 +17976,6 @@ var require_eventsource_stream = __commonJS({ var CR2 = 13; var COLON2 = 58; var SPACE2 = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i2 = start; i2 < buffer.length; i2++) { - if (buffer[i2] < 48 || buffer[i2] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i2 = start; i2 < buffer.length; i2++) { - if (buffer[i2] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i2 = 0; i2 < length; i2++) { - if (line[i2] !== field[i2]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18364,13 +17995,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18401,30 +18029,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF2) { + if (this.buffer[this.pos] === LF2) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF2 || byte === CR2) { - if (byte === CR2) { + if (this.buffer[this.pos] === LF2 || this.buffer[this.pos] === CR2) { + if (this.buffer[this.pos] === CR2) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18433,16 +18094,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF2 || byte === CR2) { - if (byte === CR2) { + if (this.buffer[this.pos] === LF2 || this.buffer[this.pos] === CR2) { + if (this.buffer[this.pos] === CR2) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18458,42 +18120,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE2) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18518,120 +18181,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i2 = this.lineChunkIndex; i2 <= this.chunkIndex; i2++) { - const chunk = this.chunks[i2]; - const start = i2 === this.lineChunkIndex ? this.linePos : 0; - const end = i2 === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/getArtifactInfo/index.js b/.github/actions/javascript/getArtifactInfo/index.js index b511ee174521..1d7315a4ae65 100644 --- a/.github/actions/javascript/getArtifactInfo/index.js +++ b/.github/actions/javascript/getArtifactInfo/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index c6a083ec32cf..86ebf2b747d2 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/getPreviousVersion/index.js b/.github/actions/javascript/getPreviousVersion/index.js index dc48a205f79b..0343158e5a02 100644 --- a/.github/actions/javascript/getPreviousVersion/index.js +++ b/.github/actions/javascript/getPreviousVersion/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/getPullRequestDetails/index.js b/.github/actions/javascript/getPullRequestDetails/index.js index b7443787fc9b..78b36a004849 100644 --- a/.github/actions/javascript/getPullRequestDetails/index.js +++ b/.github/actions/javascript/getPullRequestDetails/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/getPullRequestIncrementalChanges/index.js b/.github/actions/javascript/getPullRequestIncrementalChanges/index.js index e868a069ae7e..21c54003dde2 100644 --- a/.github/actions/javascript/getPullRequestIncrementalChanges/index.js +++ b/.github/actions/javascript/getPullRequestIncrementalChanges/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error3) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error3 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error3) { - util.errorRequest(client, request2, error3); - util.destroy(socket, error3); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error3) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error3 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error3) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error3 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error3 = error3 || new RequestAbortedError(); - util.errorRequest(client, request2, error3); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error3); + util.destroy(stream, err); } - util.destroy(body, error3); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error3) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error3); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error3) { - stream.off("response", onResponse); - abort(error3); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path2.length; ++i) { const code = path2.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error3, data) => { - if (error3) { - const code = error3 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error3.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error3, data) => { + if (error3) { + failWebsocketConnection(this.ws, error3.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/isAuthorizedContributor/index.js b/.github/actions/javascript/isAuthorizedContributor/index.js index d43a19fced4c..fea991ad887f 100644 --- a/.github/actions/javascript/isAuthorizedContributor/index.js +++ b/.github/actions/javascript/isAuthorizedContributor/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/isDeployChecklistLocked/index.js b/.github/actions/javascript/isDeployChecklistLocked/index.js index cfe1ac778241..ebdf2bf6961c 100644 --- a/.github/actions/javascript/isDeployChecklistLocked/index.js +++ b/.github/actions/javascript/isDeployChecklistLocked/index.js @@ -3432,7 +3432,6 @@ var require_CONST = __commonJS({ REPLACE_CARD: "replace_card", SHIP_CARD: "ship_card", REPORT_CARD_FRAUD: "report_card_fraud", - APPROVE_DIGITAL_WALLET: "approve_digital_wallet", ISSUE_CARD: "issue_card", UPDATE_CARD: "update_card", UPDATE_PERSONAL_DETAILS: "update_personal_details", @@ -22076,117 +22075,6 @@ var require_str = __commonJS({ } return parameter; } - function compare(strA, strB) { - if (strA < strB) { - return -1; - } - if (strA > strB) { - return 1; - } - return 0; - } - function caseInsensitiveCompare(strA, strB) { - const lowerCaseStrA = strA.toLocaleLowerCase(); - const lowerCaseStrB = strB.toLocaleLowerCase(); - return compare(lowerCaseStrA, lowerCaseStrB); - } - function contains(haystack, needle) { - return haystack.indexOf(needle) !== -1; - } - function cutAfter(str, substr) { - const index = str.indexOf(substr); - if (index !== -1) { - return str.substring(0, index); - } - return str; - } - function cutBefore(str, substr) { - const index = str.indexOf(substr); - if (index !== -1) { - return str.substring(index + substr.length); - } - return str; - } - function extractEmailDomain(email) { - return cutBefore(email, "@"); - } - function getExtension(url) { - var _a, _b; - if (typeof url !== "string") { - Log_1.default.warn("Str.getExtension: url is not a string", { url }); - return void 0; - } - return (_b = (_a = url.split(".").pop()) === null || _a === void 0 ? void 0 : _a.split("?")[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase(); - } - function getRawByteSize(inputChar) { - const onlyChar = String(inputChar); - const c = onlyChar.charCodeAt(0); - if (c < 1 << 7) { - return 1; - } - if (c < 1 << 11) { - return 2; - } - if (c < 1 << 16) { - return 3; - } - if (c < 1 << 21) { - return 4; - } - if (c < 1 << 26) { - return 5; - } - if (c < 1 << 31) { - return 6; - } - return Number.NaN; - } - function htmlDecode(s) { - return HtmlEntities.decode(s); - } - function htmlEncode(s) { - return HtmlEntities.encode(s); - } - function isTypeOf(obj, type) { - return Object.prototype.toString.call(obj) === `[object ${type}]`; - } - function isNumber(obj) { - return isTypeOf(obj, "Number"); - } - function isString(obj) { - return isTypeOf(obj, "String"); - } - function isUndefined(obj) { - return obj === void 0; - } - function isValidE164Phone(phone) { - return Constants.CONST.SMS.E164_REGEX.test(phone); - } - function isValidEmail(str) { - if (!str || typeof str !== "string") { - return false; - } - const unicodeVersion = punycode_1.default.toUnicode(str); - if (String(unicodeVersion).match(Constants.CONST.REG_EXP.EMOJI_RULE)) { - return false; - } - return !!String(str).match(Constants.CONST.REG_EXP.EMAIL); - } - function maskFirstNCharacters(str, num, mask) { - if (!isString(str) || !isString(mask) || str.length === 0 || !isNumber(num)) { - return str; - } - return str.substring(0, num).replaceAll(/./g, mask) + str.substring(num); - } - function removeSMSDomain(text) { - return text.replaceAll(REMOVE_SMS_DOMAIN_PATTERN, ""); - } - function removeTrailingComma(str) { - return str.trim().replaceAll(/(,$)/g, ""); - } - function startsWith(haystack, needle) { - return isString(haystack) && isString(needle) && haystack.substring(0, needle.length) === needle; - } var Str2 = { /** * Return true if the string is ending with the provided suffix @@ -22244,14 +22132,18 @@ var require_str = __commonJS({ * @param s The string to decode. * @returns The decoded string. */ - htmlDecode, + htmlDecode(s) { + return HtmlEntities.decode(s); + }, /** * HTML encodes the given string. * * @param s The string to encode. * @return string @p s HTML encoded. */ - htmlEncode, + htmlEncode(s) { + return HtmlEntities.encode(s); + }, /** * Decodes the given HTML encoded string. * @@ -22293,7 +22185,7 @@ var require_str = __commonJS({ * @returns True when first === second, ignoring HTML encoding */ htmlEncodingInsensitiveEquals(first, second) { - return first === second || htmlDecode(first) === second || htmlEncode(first) === second; + return first === second || this.htmlDecode(first) === second || this.htmlEncode(first) === second; }, /** * Creates an ID that can be used as an HTML attribute from @p str. @@ -22376,14 +22268,36 @@ var require_str = __commonJS({ * one. * @returns Byte size of the character */ - getRawByteSize, + getRawByteSize(inputChar) { + const onlyChar = String(inputChar); + const c = onlyChar.charCodeAt(0); + if (c < 1 << 7) { + return 1; + } + if (c < 1 << 11) { + return 2; + } + if (c < 1 << 16) { + return 3; + } + if (c < 1 << 21) { + return 4; + } + if (c < 1 << 26) { + return 5; + } + if (c < 1 << 31) { + return 6; + } + return Number.NaN; + }, /** * Gets the length of a string in bytes, including non-ASCII characters * @returns The number of bytes used by string */ getByteLength(input) { const stringInput = String(input); - const byteLength = Array.from(stringInput).reduce((acc, char) => acc + getRawByteSize(char), 0); + const byteLength = Array.from(stringInput).reduce((acc, char) => acc + this.getRawByteSize(char), 0); return byteLength; }, /** @@ -22395,7 +22309,7 @@ var require_str = __commonJS({ const stringInput = String(input); let totalByteLength = 0; for (let i = 0; i < stringInput.length; i++) { - const charByteSize = getRawByteSize(stringInput[i]); + const charByteSize = this.getRawByteSize(stringInput[i]); if (charByteSize + totalByteLength > maxSize) { return `${stringInput.substr(0, i - 3)}...`; } @@ -22410,7 +22324,9 @@ var require_str = __commonJS({ * @param needle The case-sensitive string to search for * @returns True if the haystack starts with the needle. */ - startsWith, + startsWith(haystack, needle) { + return this.isString(haystack) && this.isString(needle) && haystack.substring(0, needle.length) === needle; + }, /** * Gets the textual value of the given string. * @@ -22418,7 +22334,7 @@ var require_str = __commonJS({ * @returns The text from within the HTML string. */ stripHTML(str) { - if (!isString(str)) { + if (!this.isString(str)) { return ""; } return str.replaceAll(/<[^>]*>?/gm, ""); @@ -22441,7 +22357,13 @@ var require_str = __commonJS({ * @param substr The substring to search for. * @returns The cut/trimmed string. */ - cutAfter, + cutAfter(str, substr) { + const index = str.indexOf(substr); + if (index !== -1) { + return str.substring(0, index); + } + return str; + }, /** * Returns a string containing all the characters str from after the first * occurrence of substr to the end of the string. @@ -22451,7 +22373,13 @@ var require_str = __commonJS({ * @param substr The substring to search for. * @returns The cut/trimmed string. */ - cutBefore, + cutBefore(str, substr) { + const index = str.indexOf(substr); + if (index !== -1) { + return str.substring(index + substr.length); + } + return str; + }, /** * Checks that the string is a domain name (e.g. example.com) * @@ -22478,7 +22406,16 @@ var require_str = __commonJS({ * * @returns True if the string is an email */ - isValidEmail, + isValidEmail(str) { + if (!str || typeof str !== "string") { + return false; + } + const unicodeVersion = punycode_1.default.toUnicode(str); + if (String(unicodeVersion).match(Constants.CONST.REG_EXP.EMOJI_RULE)) { + return false; + } + return !!String(str).match(Constants.CONST.REG_EXP.EMAIL); + }, /** * Checks if the string is an valid email address formed during comment markdown formation. * @@ -22496,7 +22433,9 @@ var require_str = __commonJS({ * * @returns string with the trailing comma removed */ - removeTrailingComma, + removeTrailingComma(str) { + return str.trim().replaceAll(/(,$)/g, ""); + }, /** * Checks that the string is a list of coma separated email addresss. * @@ -22505,12 +22444,12 @@ var require_str = __commonJS({ * @returns True if all emails are valid or if input is empty */ areValidEmails(str) { - const string = removeTrailingComma(str); + const string = this.removeTrailingComma(str); if (string === "") { return true; } const emails = string.split(","); - const result = emails.every((email) => isValidEmail(email.trim())); + const result = emails.every((email) => this.isValidEmail(email.trim())); return result; }, /** @@ -22527,7 +22466,9 @@ var require_str = __commonJS({ * * @returns The domain name in the email address. */ - extractEmailDomain, + extractEmailDomain(email) { + return this.cutBefore(email, "@"); + }, /** * Tries to extract the company name from the given email address * (e.g. "yelp" for "joe@yelp.co.uk"). @@ -22537,7 +22478,7 @@ var require_str = __commonJS({ * @returns The company name in the email address or null. */ extractCompanyNameFromEmailDomain(email) { - const domain = extractEmailDomain(email); + const domain = this.extractEmailDomain(email); if (!domain) { return null; } @@ -22556,7 +22497,7 @@ var require_str = __commonJS({ * @returns The local part in the email address. */ extractEmailLocalPart(email) { - return cutAfter(email, "@"); + return this.cutAfter(email, "@"); }, /** * Sanitize phone number to return only numbers. Return null if non valid phone number. @@ -22614,13 +22555,13 @@ var require_str = __commonJS({ * @returns true if the length is in the range, false otherwise */ isOfLength(str, minimumLength, maximumLength) { - if (!isString(str)) { + if (!this.isString(str)) { return false; } if (str.length < minimumLength) { return false; } - if (!isUndefined(maximumLength) && str.length > maximumLength) { + if (!this.isUndefined(maximumLength) && str.length > maximumLength) { return false; } return true; @@ -22673,7 +22614,9 @@ var require_str = __commonJS({ * * @returns Returns true if the haystack contains the needle */ - contains, + contains(haystack, needle) { + return haystack.indexOf(needle) !== -1; + }, /** * Returns true if the haystack contains the needle, ignoring case * @@ -22683,7 +22626,7 @@ var require_str = __commonJS({ * @returns Returns true if the haystack contains the needle, ignoring case */ caseInsensitiveContains(haystack, needle) { - return contains(haystack.toLowerCase(), needle.toLowerCase()); + return this.contains(haystack.toLowerCase(), needle.toLowerCase()); }, /** * Case insensitive compare function @@ -22695,7 +22638,11 @@ var require_str = __commonJS({ * 1 if first string > second string * 0 if first string = second string */ - caseInsensitiveCompare, + caseInsensitiveCompare(strA, strB) { + const lowerCaseStrA = strA.toLocaleLowerCase(); + const lowerCaseStrB = strB.toLocaleLowerCase(); + return this.compare(lowerCaseStrA, lowerCaseStrB); + }, /** * Case insensitive equals * @@ -22704,7 +22651,7 @@ var require_str = __commonJS({ * @returns true when first == second except for case */ caseInsensitiveEquals(strA, strB) { - return caseInsensitiveCompare(strA, strB) === 0; + return this.caseInsensitiveCompare(strA, strB) === 0; }, /** * Compare function @@ -22716,7 +22663,15 @@ var require_str = __commonJS({ * 1 if first string > second string * 0 if first string = second string */ - compare, + compare(strA, strB) { + if (strA < strB) { + return -1; + } + if (strA > strB) { + return 1; + } + return 0; + }, /** * Check if a file extension is supported by SmartReports */ @@ -22735,37 +22690,45 @@ var require_str = __commonJS({ const accountNumber = String(num); const len = accountNumber.length; if (len < 6 || len > 20) { - return maskFirstNCharacters(accountNumber, len, "X"); + return this.maskFirstNCharacters(accountNumber, len, "X"); } if (len < 14) { - return maskFirstNCharacters(accountNumber, len - 4, "X"); + return this.maskFirstNCharacters(accountNumber, len - 4, "X"); } const first = accountNumber.substr(0, 6); const last = accountNumber.substr(7); - const masked = maskFirstNCharacters(last, len - 11, "X"); + const masked = this.maskFirstNCharacters(last, len - 11, "X"); return `${first}${masked}`; }, /** * Checks if something is a string * Stolen from underscore */ - isString, + isString(obj) { + return this.isTypeOf(obj, "String"); + }, /** * Checks if something is a number * Stolen from underscore * @param obj */ - isNumber, + isNumber(obj) { + return this.isTypeOf(obj, "Number"); + }, /** * Checks if something is a certain type * Stolen from underscore */ - isTypeOf, + isTypeOf(obj, type) { + return Object.prototype.toString.call(obj) === `[object ${type}]`; + }, /** * Checks to see if something is undefined * Stolen from underscore */ - isUndefined, + isUndefined(obj) { + return obj === void 0; + }, /** * Replace first N characters of the string with maskChar * eg: maskFirstNCharacters( '1234567890', 6, 'X' ) yields XXXXXX7890 @@ -22774,7 +22737,12 @@ var require_str = __commonJS({ * @param mask String we want replace the first N chars with * @returns Masked string */ - maskFirstNCharacters, + maskFirstNCharacters(str, num, mask) { + if (!this.isString(str) || !this.isString(mask) || str.length === 0 || !this.isNumber(num)) { + return str; + } + return str.substring(0, num).replaceAll(/./g, mask) + str.substring(num); + }, /** * Trim a string */ @@ -22786,7 +22754,7 @@ var require_str = __commonJS({ * @param percentageString The percentage as a string */ percentageStringToNumber(percentageString) { - return Number(cutAfter(percentageString, "%")); + return Number(this.cutAfter(percentageString, "%")); }, /** * Remove all the spaces from a string @@ -22830,7 +22798,7 @@ var require_str = __commonJS({ * Converts a value to boolean, case-insensitive. */ toBool(value) { - if (isString(value)) { + if (this.isString(value)) { return value.toLowerCase() === "true"; } return !!value; @@ -22880,7 +22848,9 @@ var require_str = __commonJS({ /** * Check for whether a phone number is valid according to E.164 standard. */ - isValidE164Phone, + isValidE164Phone(phone) { + return Constants.CONST.SMS.E164_REGEX.test(phone); + }, /** * Check for whether a phone number is valid in different formats/standards. For example: * significant: 4404589784 @@ -22906,12 +22876,14 @@ var require_str = __commonJS({ /** * Returns text without our SMS domain */ - removeSMSDomain, + removeSMSDomain(text) { + return text.replaceAll(REMOVE_SMS_DOMAIN_PATTERN, ""); + }, /** * Returns true if the text is a valid E.164 phone number with our SMS domain removed */ isSMSLogin(text) { - return isValidE164Phone(removeSMSDomain(text)); + return this.isValidE164Phone(this.removeSMSDomain(text)); }, /** * This method will return all matches of a single regex like preg_match_all() in PHP. This is not a common part of @@ -22964,7 +22936,7 @@ var require_str = __commonJS({ return url; } const website = match[3] ? match[2] : `${defaultScheme}://${match[2]}`; - return website.toLowerCase() + cutBefore(match[1], match[2]); + return website.toLowerCase() + this.cutBefore(match[1], match[2]); }, /** * Checks if parameter is a string or function @@ -22976,7 +22948,14 @@ var require_str = __commonJS({ * Get file extension for a given url with or * without query parameters */ - getExtension, + getExtension(url) { + var _a, _b; + if (typeof url !== "string") { + Log_1.default.warn("Str.getExtension: url is not a string", { url }); + return void 0; + } + return (_b = (_a = url.split(".").pop()) === null || _a === void 0 ? void 0 : _a.split("?")[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase(); + }, /** * Takes in a URL and checks if the file extension is PDF * @@ -22984,7 +22963,7 @@ var require_str = __commonJS({ * @returns Whether file path is PDF or not */ isPDF(url) { - return getExtension(url) === "pdf"; + return this.getExtension(url) === "pdf"; }, /** * Takes in a URL and checks if the file extension is an image @@ -22995,7 +22974,7 @@ var require_str = __commonJS({ * https://reactnative.dev/docs/image#source */ isImage(url) { - const extension = getExtension(url); + const extension = this.getExtension(url); if (!extension) { return false; } @@ -23011,7 +22990,7 @@ var require_str = __commonJS({ * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs */ isVideo(url) { - const extension = getExtension(url); + const extension = this.getExtension(url); if (!extension) { return false; } @@ -23024,7 +23003,7 @@ var require_str = __commonJS({ * @returns True if is a domain account email, otherwise false. */ isDomainEmail(email) { - return startsWith(email, "+@"); + return this.startsWith(email, "+@"); }, /** * Find the minimum indentation of any line in the string, @@ -24162,17 +24141,13 @@ ${g2} }, { name: "anchor", - regex: /(\]\()?<(a)[^><]*href\s*=\s*(['"])(.*?)\3(?:".*?"|'.*?'|[^'"><])*>([\s\S]*?)<\/\2>(?![^<]*(<\/pre>|<\/code>))/gi, - replacement: (_extras, _match, g1, _g2, _g3, g4, g5) => { - const incompleteLinkStart = g1 !== null && g1 !== void 0 ? g1 : ""; - const email = g4.startsWith("mailto:") ? g4.slice(7) : ""; - if (email === g5) { - return `${incompleteLinkStart}${email}`; - } - if (incompleteLinkStart && (g4 === g5 || g4 === `https://${g5}`)) { - return `${incompleteLinkStart}${g5}`; + regex: /<(a)[^><]*href\s*=\s*(['"])(.*?)\2(?:".*?"|'.*?'|[^'"><])*>([\s\S]*?)<\/\1>(?![^<]*(<\/pre>|<\/code>))/gi, + replacement: (_extras, _match, _g1, _g2, g3, g4) => { + const email = g3.startsWith("mailto:") ? g3.slice(7) : ""; + if (email === g4) { + return email; } - return `${incompleteLinkStart}[${g5}](${email || g4})`; + return `[${g4}](${email || g3})`; } }, { @@ -28472,66 +28447,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -28598,11 +28517,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -28614,9 +28529,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -28726,21 +28638,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -32347,7 +32251,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -32394,9 +32297,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -32559,55 +32459,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); - } + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -32627,10 +32496,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -32674,7 +32539,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -32699,10 +32564,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -32711,10 +32575,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -32840,7 +32700,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -32884,19 +32743,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -32911,10 +32763,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -32922,10 +32771,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -32974,7 +32822,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -32992,23 +32840,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -33021,29 +32852,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -33074,16 +32882,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -33104,18 +32904,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -33471,7 +33264,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -33532,10 +33324,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -33699,22 +33487,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -33729,42 +33511,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -34325,10 +34083,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -34834,8 +34591,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -35006,6 +34763,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -35026,7 +34784,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -35226,6 +34983,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -35235,7 +34993,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -35676,24 +35433,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -35747,7 +35486,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -35757,17 +35495,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -35829,9 +35556,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -35880,21 +35605,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -35902,7 +35615,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -35910,11 +35622,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -35934,7 +35641,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -35962,7 +35668,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -42761,48 +42467,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -42885,11 +42557,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -43019,14 +42687,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -43848,7 +43520,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -43954,26 +43626,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -43992,12 +43669,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -44007,17 +43692,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -44048,14 +43735,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -44063,21 +43744,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -44092,13 +43770,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -44158,9 +43829,6 @@ var require_receiver = __commonJS({ 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) { @@ -44181,9 +43849,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -44197,9 +43862,6 @@ var require_receiver = __commonJS({ } 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(); @@ -44210,46 +43872,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -44292,26 +43940,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -44523,6 +44151,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -44566,6 +44196,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -44749,13 +44382,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -44830,6 +44457,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -44908,40 +44548,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -44961,13 +44567,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -44998,30 +44601,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -45030,16 +44666,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -45055,42 +44692,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -45115,120 +44753,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/index.js b/.github/actions/javascript/markPullRequestsAsDeployed/index.js index 5eca45f374da..62a50ec22616 100644 --- a/.github/actions/javascript/markPullRequestsAsDeployed/index.js +++ b/.github/actions/javascript/markPullRequestsAsDeployed/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/postOrReplaceComment/index.js b/.github/actions/javascript/postOrReplaceComment/index.js index 195707dedc9f..fb9eb8df9e7b 100644 --- a/.github/actions/javascript/postOrReplaceComment/index.js +++ b/.github/actions/javascript/postOrReplaceComment/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/proposalPoliceComment/index.js b/.github/actions/javascript/proposalPoliceComment/index.js index 58a12c5fb27a..126b34462df4 100644 --- a/.github/actions/javascript/proposalPoliceComment/index.js +++ b/.github/actions/javascript/proposalPoliceComment/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str2 = `${val[i]}`; - if (!isValidHeaderValue(str2)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str2); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); - } + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message2 = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message2 = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + throw new HTTPParserError(message2, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message2 = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message2 = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message2, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } - return; - } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path2.length; ++i) { const code = path2.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { @@ -24691,7 +24246,6 @@ var require_CONST = __commonJS({ REPLACE_CARD: "replace_card", SHIP_CARD: "ship_card", REPORT_CARD_FRAUD: "report_card_fraud", - APPROVE_DIGITAL_WALLET: "approve_digital_wallet", ISSUE_CARD: "issue_card", UPDATE_CARD: "update_card", UPDATE_PERSONAL_DETAILS: "update_personal_details", @@ -43335,117 +42889,6 @@ var require_str = __commonJS({ } return parameter; } - function compare(strA, strB) { - if (strA < strB) { - return -1; - } - if (strA > strB) { - return 1; - } - return 0; - } - function caseInsensitiveCompare(strA, strB) { - const lowerCaseStrA = strA.toLocaleLowerCase(); - const lowerCaseStrB = strB.toLocaleLowerCase(); - return compare(lowerCaseStrA, lowerCaseStrB); - } - function contains(haystack, needle) { - return haystack.indexOf(needle) !== -1; - } - function cutAfter(str2, substr) { - const index = str2.indexOf(substr); - if (index !== -1) { - return str2.substring(0, index); - } - return str2; - } - function cutBefore(str2, substr) { - const index = str2.indexOf(substr); - if (index !== -1) { - return str2.substring(index + substr.length); - } - return str2; - } - function extractEmailDomain(email) { - return cutBefore(email, "@"); - } - function getExtension(url) { - var _a3, _b; - if (typeof url !== "string") { - Log_1.default.warn("Str.getExtension: url is not a string", { url }); - return void 0; - } - return (_b = (_a3 = url.split(".").pop()) === null || _a3 === void 0 ? void 0 : _a3.split("?")[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase(); - } - function getRawByteSize(inputChar) { - const onlyChar = String(inputChar); - const c = onlyChar.charCodeAt(0); - if (c < 1 << 7) { - return 1; - } - if (c < 1 << 11) { - return 2; - } - if (c < 1 << 16) { - return 3; - } - if (c < 1 << 21) { - return 4; - } - if (c < 1 << 26) { - return 5; - } - if (c < 1 << 31) { - return 6; - } - return Number.NaN; - } - function htmlDecode(s) { - return HtmlEntities.decode(s); - } - function htmlEncode(s) { - return HtmlEntities.encode(s); - } - function isTypeOf(obj, type) { - return Object.prototype.toString.call(obj) === `[object ${type}]`; - } - function isNumber(obj) { - return isTypeOf(obj, "Number"); - } - function isString(obj) { - return isTypeOf(obj, "String"); - } - function isUndefined(obj) { - return obj === void 0; - } - function isValidE164Phone(phone) { - return Constants.CONST.SMS.E164_REGEX.test(phone); - } - function isValidEmail(str2) { - if (!str2 || typeof str2 !== "string") { - return false; - } - const unicodeVersion = punycode_1.default.toUnicode(str2); - if (String(unicodeVersion).match(Constants.CONST.REG_EXP.EMOJI_RULE)) { - return false; - } - return !!String(str2).match(Constants.CONST.REG_EXP.EMAIL); - } - function maskFirstNCharacters(str2, num, mask) { - if (!isString(str2) || !isString(mask) || str2.length === 0 || !isNumber(num)) { - return str2; - } - return str2.substring(0, num).replaceAll(/./g, mask) + str2.substring(num); - } - function removeSMSDomain(text) { - return text.replaceAll(REMOVE_SMS_DOMAIN_PATTERN, ""); - } - function removeTrailingComma(str2) { - return str2.trim().replaceAll(/(,$)/g, ""); - } - function startsWith(haystack, needle) { - return isString(haystack) && isString(needle) && haystack.substring(0, needle.length) === needle; - } var Str6 = { /** * Return true if the string is ending with the provided suffix @@ -43503,14 +42946,18 @@ var require_str = __commonJS({ * @param s The string to decode. * @returns The decoded string. */ - htmlDecode, + htmlDecode(s) { + return HtmlEntities.decode(s); + }, /** * HTML encodes the given string. * * @param s The string to encode. * @return string @p s HTML encoded. */ - htmlEncode, + htmlEncode(s) { + return HtmlEntities.encode(s); + }, /** * Decodes the given HTML encoded string. * @@ -43552,7 +42999,7 @@ var require_str = __commonJS({ * @returns True when first === second, ignoring HTML encoding */ htmlEncodingInsensitiveEquals(first, second) { - return first === second || htmlDecode(first) === second || htmlEncode(first) === second; + return first === second || this.htmlDecode(first) === second || this.htmlEncode(first) === second; }, /** * Creates an ID that can be used as an HTML attribute from @p str. @@ -43635,14 +43082,36 @@ var require_str = __commonJS({ * one. * @returns Byte size of the character */ - getRawByteSize, + getRawByteSize(inputChar) { + const onlyChar = String(inputChar); + const c = onlyChar.charCodeAt(0); + if (c < 1 << 7) { + return 1; + } + if (c < 1 << 11) { + return 2; + } + if (c < 1 << 16) { + return 3; + } + if (c < 1 << 21) { + return 4; + } + if (c < 1 << 26) { + return 5; + } + if (c < 1 << 31) { + return 6; + } + return Number.NaN; + }, /** * Gets the length of a string in bytes, including non-ASCII characters * @returns The number of bytes used by string */ getByteLength(input) { const stringInput = String(input); - const byteLength = Array.from(stringInput).reduce((acc, char) => acc + getRawByteSize(char), 0); + const byteLength = Array.from(stringInput).reduce((acc, char) => acc + this.getRawByteSize(char), 0); return byteLength; }, /** @@ -43654,7 +43123,7 @@ var require_str = __commonJS({ const stringInput = String(input); let totalByteLength = 0; for (let i = 0; i < stringInput.length; i++) { - const charByteSize = getRawByteSize(stringInput[i]); + const charByteSize = this.getRawByteSize(stringInput[i]); if (charByteSize + totalByteLength > maxSize) { return `${stringInput.substr(0, i - 3)}...`; } @@ -43669,7 +43138,9 @@ var require_str = __commonJS({ * @param needle The case-sensitive string to search for * @returns True if the haystack starts with the needle. */ - startsWith, + startsWith(haystack, needle) { + return this.isString(haystack) && this.isString(needle) && haystack.substring(0, needle.length) === needle; + }, /** * Gets the textual value of the given string. * @@ -43677,7 +43148,7 @@ var require_str = __commonJS({ * @returns The text from within the HTML string. */ stripHTML(str2) { - if (!isString(str2)) { + if (!this.isString(str2)) { return ""; } return str2.replaceAll(/<[^>]*>?/gm, ""); @@ -43700,7 +43171,13 @@ var require_str = __commonJS({ * @param substr The substring to search for. * @returns The cut/trimmed string. */ - cutAfter, + cutAfter(str2, substr) { + const index = str2.indexOf(substr); + if (index !== -1) { + return str2.substring(0, index); + } + return str2; + }, /** * Returns a string containing all the characters str from after the first * occurrence of substr to the end of the string. @@ -43710,7 +43187,13 @@ var require_str = __commonJS({ * @param substr The substring to search for. * @returns The cut/trimmed string. */ - cutBefore, + cutBefore(str2, substr) { + const index = str2.indexOf(substr); + if (index !== -1) { + return str2.substring(index + substr.length); + } + return str2; + }, /** * Checks that the string is a domain name (e.g. example.com) * @@ -43737,7 +43220,16 @@ var require_str = __commonJS({ * * @returns True if the string is an email */ - isValidEmail, + isValidEmail(str2) { + if (!str2 || typeof str2 !== "string") { + return false; + } + const unicodeVersion = punycode_1.default.toUnicode(str2); + if (String(unicodeVersion).match(Constants.CONST.REG_EXP.EMOJI_RULE)) { + return false; + } + return !!String(str2).match(Constants.CONST.REG_EXP.EMAIL); + }, /** * Checks if the string is an valid email address formed during comment markdown formation. * @@ -43755,7 +43247,9 @@ var require_str = __commonJS({ * * @returns string with the trailing comma removed */ - removeTrailingComma, + removeTrailingComma(str2) { + return str2.trim().replaceAll(/(,$)/g, ""); + }, /** * Checks that the string is a list of coma separated email addresss. * @@ -43764,12 +43258,12 @@ var require_str = __commonJS({ * @returns True if all emails are valid or if input is empty */ areValidEmails(str2) { - const string = removeTrailingComma(str2); + const string = this.removeTrailingComma(str2); if (string === "") { return true; } const emails = string.split(","); - const result = emails.every((email) => isValidEmail(email.trim())); + const result = emails.every((email) => this.isValidEmail(email.trim())); return result; }, /** @@ -43786,7 +43280,9 @@ var require_str = __commonJS({ * * @returns The domain name in the email address. */ - extractEmailDomain, + extractEmailDomain(email) { + return this.cutBefore(email, "@"); + }, /** * Tries to extract the company name from the given email address * (e.g. "yelp" for "joe@yelp.co.uk"). @@ -43796,7 +43292,7 @@ var require_str = __commonJS({ * @returns The company name in the email address or null. */ extractCompanyNameFromEmailDomain(email) { - const domain = extractEmailDomain(email); + const domain = this.extractEmailDomain(email); if (!domain) { return null; } @@ -43815,7 +43311,7 @@ var require_str = __commonJS({ * @returns The local part in the email address. */ extractEmailLocalPart(email) { - return cutAfter(email, "@"); + return this.cutAfter(email, "@"); }, /** * Sanitize phone number to return only numbers. Return null if non valid phone number. @@ -43873,13 +43369,13 @@ var require_str = __commonJS({ * @returns true if the length is in the range, false otherwise */ isOfLength(str2, minimumLength, maximumLength) { - if (!isString(str2)) { + if (!this.isString(str2)) { return false; } if (str2.length < minimumLength) { return false; } - if (!isUndefined(maximumLength) && str2.length > maximumLength) { + if (!this.isUndefined(maximumLength) && str2.length > maximumLength) { return false; } return true; @@ -43932,7 +43428,9 @@ var require_str = __commonJS({ * * @returns Returns true if the haystack contains the needle */ - contains, + contains(haystack, needle) { + return haystack.indexOf(needle) !== -1; + }, /** * Returns true if the haystack contains the needle, ignoring case * @@ -43942,7 +43440,7 @@ var require_str = __commonJS({ * @returns Returns true if the haystack contains the needle, ignoring case */ caseInsensitiveContains(haystack, needle) { - return contains(haystack.toLowerCase(), needle.toLowerCase()); + return this.contains(haystack.toLowerCase(), needle.toLowerCase()); }, /** * Case insensitive compare function @@ -43954,7 +43452,11 @@ var require_str = __commonJS({ * 1 if first string > second string * 0 if first string = second string */ - caseInsensitiveCompare, + caseInsensitiveCompare(strA, strB) { + const lowerCaseStrA = strA.toLocaleLowerCase(); + const lowerCaseStrB = strB.toLocaleLowerCase(); + return this.compare(lowerCaseStrA, lowerCaseStrB); + }, /** * Case insensitive equals * @@ -43963,7 +43465,7 @@ var require_str = __commonJS({ * @returns true when first == second except for case */ caseInsensitiveEquals(strA, strB) { - return caseInsensitiveCompare(strA, strB) === 0; + return this.caseInsensitiveCompare(strA, strB) === 0; }, /** * Compare function @@ -43975,7 +43477,15 @@ var require_str = __commonJS({ * 1 if first string > second string * 0 if first string = second string */ - compare, + compare(strA, strB) { + if (strA < strB) { + return -1; + } + if (strA > strB) { + return 1; + } + return 0; + }, /** * Check if a file extension is supported by SmartReports */ @@ -43994,37 +43504,45 @@ var require_str = __commonJS({ const accountNumber = String(num); const len = accountNumber.length; if (len < 6 || len > 20) { - return maskFirstNCharacters(accountNumber, len, "X"); + return this.maskFirstNCharacters(accountNumber, len, "X"); } if (len < 14) { - return maskFirstNCharacters(accountNumber, len - 4, "X"); + return this.maskFirstNCharacters(accountNumber, len - 4, "X"); } const first = accountNumber.substr(0, 6); const last = accountNumber.substr(7); - const masked = maskFirstNCharacters(last, len - 11, "X"); + const masked = this.maskFirstNCharacters(last, len - 11, "X"); return `${first}${masked}`; }, /** * Checks if something is a string * Stolen from underscore */ - isString, + isString(obj) { + return this.isTypeOf(obj, "String"); + }, /** * Checks if something is a number * Stolen from underscore * @param obj */ - isNumber, + isNumber(obj) { + return this.isTypeOf(obj, "Number"); + }, /** * Checks if something is a certain type * Stolen from underscore */ - isTypeOf, + isTypeOf(obj, type) { + return Object.prototype.toString.call(obj) === `[object ${type}]`; + }, /** * Checks to see if something is undefined * Stolen from underscore */ - isUndefined, + isUndefined(obj) { + return obj === void 0; + }, /** * Replace first N characters of the string with maskChar * eg: maskFirstNCharacters( '1234567890', 6, 'X' ) yields XXXXXX7890 @@ -44033,7 +43551,12 @@ var require_str = __commonJS({ * @param mask String we want replace the first N chars with * @returns Masked string */ - maskFirstNCharacters, + maskFirstNCharacters(str2, num, mask) { + if (!this.isString(str2) || !this.isString(mask) || str2.length === 0 || !this.isNumber(num)) { + return str2; + } + return str2.substring(0, num).replaceAll(/./g, mask) + str2.substring(num); + }, /** * Trim a string */ @@ -44045,7 +43568,7 @@ var require_str = __commonJS({ * @param percentageString The percentage as a string */ percentageStringToNumber(percentageString) { - return Number(cutAfter(percentageString, "%")); + return Number(this.cutAfter(percentageString, "%")); }, /** * Remove all the spaces from a string @@ -44089,7 +43612,7 @@ var require_str = __commonJS({ * Converts a value to boolean, case-insensitive. */ toBool(value) { - if (isString(value)) { + if (this.isString(value)) { return value.toLowerCase() === "true"; } return !!value; @@ -44139,7 +43662,9 @@ var require_str = __commonJS({ /** * Check for whether a phone number is valid according to E.164 standard. */ - isValidE164Phone, + isValidE164Phone(phone) { + return Constants.CONST.SMS.E164_REGEX.test(phone); + }, /** * Check for whether a phone number is valid in different formats/standards. For example: * significant: 4404589784 @@ -44165,12 +43690,14 @@ var require_str = __commonJS({ /** * Returns text without our SMS domain */ - removeSMSDomain, + removeSMSDomain(text) { + return text.replaceAll(REMOVE_SMS_DOMAIN_PATTERN, ""); + }, /** * Returns true if the text is a valid E.164 phone number with our SMS domain removed */ isSMSLogin(text) { - return isValidE164Phone(removeSMSDomain(text)); + return this.isValidE164Phone(this.removeSMSDomain(text)); }, /** * This method will return all matches of a single regex like preg_match_all() in PHP. This is not a common part of @@ -44223,7 +43750,7 @@ var require_str = __commonJS({ return url; } const website = match2[3] ? match2[2] : `${defaultScheme}://${match2[2]}`; - return website.toLowerCase() + cutBefore(match2[1], match2[2]); + return website.toLowerCase() + this.cutBefore(match2[1], match2[2]); }, /** * Checks if parameter is a string or function @@ -44235,7 +43762,14 @@ var require_str = __commonJS({ * Get file extension for a given url with or * without query parameters */ - getExtension, + getExtension(url) { + var _a3, _b; + if (typeof url !== "string") { + Log_1.default.warn("Str.getExtension: url is not a string", { url }); + return void 0; + } + return (_b = (_a3 = url.split(".").pop()) === null || _a3 === void 0 ? void 0 : _a3.split("?")[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase(); + }, /** * Takes in a URL and checks if the file extension is PDF * @@ -44243,7 +43777,7 @@ var require_str = __commonJS({ * @returns Whether file path is PDF or not */ isPDF(url) { - return getExtension(url) === "pdf"; + return this.getExtension(url) === "pdf"; }, /** * Takes in a URL and checks if the file extension is an image @@ -44254,7 +43788,7 @@ var require_str = __commonJS({ * https://reactnative.dev/docs/image#source */ isImage(url) { - const extension = getExtension(url); + const extension = this.getExtension(url); if (!extension) { return false; } @@ -44270,7 +43804,7 @@ var require_str = __commonJS({ * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs */ isVideo(url) { - const extension = getExtension(url); + const extension = this.getExtension(url); if (!extension) { return false; } @@ -44283,7 +43817,7 @@ var require_str = __commonJS({ * @returns True if is a domain account email, otherwise false. */ isDomainEmail(email) { - return startsWith(email, "+@"); + return this.startsWith(email, "+@"); }, /** * Find the minimum indentation of any line in the string, @@ -45421,17 +44955,13 @@ ${g2} }, { name: "anchor", - regex: /(\]\()?<(a)[^><]*href\s*=\s*(['"])(.*?)\3(?:".*?"|'.*?'|[^'"><])*>([\s\S]*?)<\/\2>(?![^<]*(<\/pre>|<\/code>))/gi, - replacement: (_extras, _match, g1, _g2, _g3, g4, g5) => { - const incompleteLinkStart = g1 !== null && g1 !== void 0 ? g1 : ""; - const email = g4.startsWith("mailto:") ? g4.slice(7) : ""; - if (email === g5) { - return `${incompleteLinkStart}${email}`; - } - if (incompleteLinkStart && (g4 === g5 || g4 === `https://${g5}`)) { - return `${incompleteLinkStart}${g5}`; + regex: /<(a)[^><]*href\s*=\s*(['"])(.*?)\2(?:".*?"|'.*?'|[^'"><])*>([\s\S]*?)<\/\1>(?![^<]*(<\/pre>|<\/code>))/gi, + replacement: (_extras, _match, _g1, _g2, g3, g4) => { + const email = g3.startsWith("mailto:") ? g3.slice(7) : ""; + if (email === g4) { + return email; } - return `${incompleteLinkStart}[${g5}](${email || g4})`; + return `[${g4}](${email || g3})`; } }, { diff --git a/.github/actions/javascript/reopenIssueWithComment/index.js b/.github/actions/javascript/reopenIssueWithComment/index.js index 2fe118ee3e64..f237f20694fd 100644 --- a/.github/actions/javascript/reopenIssueWithComment/index.js +++ b/.github/actions/javascript/reopenIssueWithComment/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/reviewerChecklist/index.js b/.github/actions/javascript/reviewerChecklist/index.js index 8e220a2cf59e..a9419acf5a2e 100644 --- a/.github/actions/javascript/reviewerChecklist/index.js +++ b/.github/actions/javascript/reviewerChecklist/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/validateReassureOutput/index.js b/.github/actions/javascript/validateReassureOutput/index.js index e511f56ffd08..b26522496b9c 100644 --- a/.github/actions/javascript/validateReassureOutput/index.js +++ b/.github/actions/javascript/validateReassureOutput/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { 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; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request, error2); - util.destroy(socket, error2); + request.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { 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; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request.aborted) { + const abort = (err) => { + if (request.aborted || request.completed) { return; } - if (request.completed) { - if (request.upgrade || request.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } - return; - } - util.errorRequest(client, request, error2 || new RequestAbortedError()); + util.errorRequest(client, request, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request.aborted) { + const abort = (err) => { + if (request.aborted || request.completed) { return; } - if (request.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } - return; - } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request.onUpgradeError(error2); - }; - const onReady = () => { - try { - request.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/verifySignedCommits/index.js b/.github/actions/javascript/verifySignedCommits/index.js index d982728230d3..087b5df387fd 100644 --- a/.github/actions/javascript/verifySignedCommits/index.js +++ b/.github/actions/javascript/verifySignedCommits/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/.github/actions/javascript/verifyStagingBuildsSucceeded/index.js b/.github/actions/javascript/verifyStagingBuildsSucceeded/index.js index d5508591a07b..1e9b71a5c3e0 100644 --- a/.github/actions/javascript/verifyStagingBuildsSucceeded/index.js +++ b/.github/actions/javascript/verifyStagingBuildsSucceeded/index.js @@ -1863,66 +1863,10 @@ var require_request = __commonJS({ return false; } } - /** - * @param {number|null} statusCode - * @param {Buffer[]|null} headers - * @param {import('node:stream').Duplex} socket - * @param {string} [statusText] - */ - onUpgrade(statusCode, headers, socket, statusText = "") { - this.onFinally(); + onUpgrade(statusCode, headers, socket) { assert(!this.aborted); assert(!this.completed); - if (statusCode !== null) { - this.#publishUpgradeHeaders(statusCode, headers, statusText); - } - const result = this[kHandler].onUpgrade(statusCode, headers, socket); - if (!this.aborted) { - this.completed = true; - if (statusCode !== null) { - this.#publishUpgradeTrailers(); - } - } - return result; - } - /** - * @param {number} statusCode - * @param {import('node:http2').IncomingHttpHeaders} headers - * @param {(headers: import('node:http2').IncomingHttpHeaders) => Buffer[]} parseHeaders - * @param {string} [statusText] - */ - onUpgradeResponse(statusCode, headers, parseHeaders, statusText = "") { - assert(!this.aborted); - assert(this.completed); - if (channels.headers.hasSubscribers) { - this.#publishUpgradeHeaders(statusCode, parseHeaders(headers), statusText); - } - this.#publishUpgradeTrailers(); - } - /** - * @param {Error} error - */ - onUpgradeError(error2) { - assert(!this.aborted); - assert(this.completed); - if (channels.error.hasSubscribers) { - channels.error.publish({ request: this, error: error2 }); - } - } - /** - * @param {number} statusCode - * @param {Buffer[]} headers - * @param {string} statusText - */ - #publishUpgradeHeaders(statusCode, headers, statusText) { - if (channels.headers.hasSubscribers) { - channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); - } - } - #publishUpgradeTrailers() { - if (channels.trailers.hasSubscribers) { - channels.trailers.publish({ request: this, trailers: [] }); - } + return this[kHandler].onUpgrade(statusCode, headers, socket); } onComplete(trailers) { this.onFinally(); @@ -1989,11 +1933,7 @@ var require_request = __commonJS({ } else if (typeof val[i] === "object") { throw new InvalidArgumentError(`invalid ${key} header`); } else { - const str = `${val[i]}`; - if (!isValidHeaderValue(str)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } - arr.push(str); + arr.push(`${val[i]}`); } } val = arr; @@ -2005,9 +1945,6 @@ var require_request = __commonJS({ val = ""; } else { val = `${val}`; - if (!isValidHeaderValue(val)) { - throw new InvalidArgumentError(`invalid ${key} header`); - } } if (headerName === "host") { if (request2.host !== null) { @@ -2117,21 +2054,13 @@ var require_dispatcher_base = __commonJS({ var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); - var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); var DispatcherBase = class 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() { return this[kDestroyed]; @@ -5738,7 +5667,6 @@ var require_client_h1 = __commonJS({ RequestContentLengthMismatchError, ResponseContentLengthMismatchError, RequestAbortedError, - InvalidArgumentError, HeadersTimeoutError, HeadersOverflowError, SocketError, @@ -5785,9 +5713,6 @@ var require_client_h1 = __commonJS({ var FastBuffer = Buffer[Symbol.species]; var addListener = util.addListener; var removeAllListeners = util.removeAllListeners; - var kIdleSocketValidation = /* @__PURE__ */ Symbol("kIdleSocketValidation"); - var kIdleSocketValidationTimeout = /* @__PURE__ */ Symbol("kIdleSocketValidationTimeout"); - var kSocketUsed = /* @__PURE__ */ Symbol("kSocketUsed"); var extractBody; async function lazyllhttp() { const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; @@ -5950,55 +5875,24 @@ var require_client_h1 = __commonJS({ currentBufferRef = null; } const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; - if (ret !== constants3.ERROR.OK) { - const body = data.subarray(offset); - if (ret === constants3.ERROR.PAUSED_UPGRADE) { - this.onUpgrade(body); - } else if (ret === constants3.ERROR.PAUSED) { - this.paused = true; - socket.unshift(body); - } else { - throw this.createError(ret, body); + if (ret === constants3.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(data.slice(offset)); + } else if (ret === constants3.ERROR.PAUSED) { + this.paused = true; + socket.unshift(data.slice(offset)); + } else if (ret !== constants3.ERROR.OK) { + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; } + throw new HTTPParserError(message, constants3.ERROR[ret], data.slice(offset)); } } 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 === constants3.ERROR.OK) { - return null; - } - if (ret === constants3.ERROR.PAUSED || ret === constants3.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(); - } - const ptr = llhttp.llhttp_get_error_reason(this.ptr); - let message = ""; - if (ptr) { - const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); - message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; - } - return new HTTPParserError(message, constants3.ERROR[ret], data); - } destroy() { assert(this.ptr != null); assert(currentParser == null); @@ -6018,10 +5912,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6065,7 +5955,7 @@ var require_client_h1 = __commonJS({ } } onUpgrade(head) { - const { upgrade, client, socket, headers, statusCode, statusText } = this; + const { upgrade, client, socket, headers, statusCode } = this; assert(upgrade); assert(client[kSocket] === socket); assert(!socket.destroyed); @@ -6090,10 +5980,9 @@ var require_client_h1 = __commonJS({ client[kQueue][client[kRunningIdx]++] = null; client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); try { - request2.onUpgrade(statusCode, headers, socket, statusText); - } catch (error2) { - util.errorRequest(client, request2, error2); - util.destroy(socket, error2); + request2.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); } client[kResume](); } @@ -6102,10 +5991,6 @@ var require_client_h1 = __commonJS({ if (socket.destroyed) { return -1; } - if (client[kRunning] === 0) { - util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); - return -1; - } const request2 = client[kQueue][client[kRunningIdx]]; if (!request2) { return -1; @@ -6231,7 +6116,6 @@ var require_client_h1 = __commonJS({ } request2.onComplete(headers); client[kQueue][client[kRunningIdx]++] = null; - socket[kSocketUsed] = true; if (socket[kWriting]) { assert(client[kRunning] === 0); util.destroy(socket, new InformationalError("reset")); @@ -6275,19 +6159,12 @@ var require_client_h1 = __commonJS({ 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) { assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); const parser = this[kParser]; if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - this[kError] = parserErr; - this[kClient][kOnError](parserErr); - } + parser.onMessageComplete(); return; } this[kError] = err; @@ -6302,10 +6179,7 @@ var require_client_h1 = __commonJS({ addListener(socket, "end", function() { const parser = this[kParser]; if (parser.statusCode && !parser.shouldKeepAlive) { - const parserErr = parser.finish(); - if (parserErr) { - util.destroy(this, parserErr); - } + parser.onMessageComplete(); return; } util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); @@ -6313,10 +6187,9 @@ var require_client_h1 = __commonJS({ addListener(socket, "close", function() { const client2 = this[kClient]; const parser = this[kParser]; - clearIdleSocketValidation(this); if (parser) { if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { - this[kError] = parser.finish() || this[kError]; + parser.onMessageComplete(); } this[kParser].destroy(); this[kParser] = null; @@ -6365,7 +6238,7 @@ var require_client_h1 = __commonJS({ return socket.destroyed; }, busy(request2) { - if (socket[kWriting] || socket[kReset] || socket[kBlocking] || socket[kIdleSocketValidation] === 1) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { return true; } if (request2) { @@ -6383,23 +6256,6 @@ var require_client_h1 = __commonJS({ } }; } - function clearIdleSocketValidation(socket) { - if (socket[kIdleSocketValidationTimeout]) { - clearImmediate(socket[kIdleSocketValidationTimeout]); - socket[kIdleSocketValidationTimeout] = null; - } - socket[kIdleSocketValidation] = 0; - } - function scheduleIdleSocketValidation(client, socket) { - socket[kIdleSocketValidation] = 1; - socket[kIdleSocketValidationTimeout] = setImmediate(() => { - socket[kIdleSocketValidationTimeout] = null; - socket[kIdleSocketValidation] = 2; - if (client[kSocket] === socket && !socket.destroyed) { - client[kResume](); - } - }); - } function resumeH1(client) { const socket = client[kSocket]; if (socket && !socket.destroyed) { @@ -6412,29 +6268,6 @@ var require_client_h1 = __commonJS({ socket.ref(); 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); @@ -6465,16 +6298,8 @@ var require_client_h1 = __commonJS({ } body = bodyStream.stream; contentLength = bodyStream.length; - } else if (util.isBlobLike(body) && request2.contentType == null) { - const contentType = body.type; - if (contentType) { - const contentTypeValue = `${contentType}`; - if (!util.isValidHeaderValue(contentTypeValue)) { - util.errorRequest(client, request2, new InvalidArgumentError("invalid content-type header")); - return false; - } - headers.push("content-type", contentTypeValue); - } + } else if (util.isBlobLike(body) && request2.contentType == null && body.type) { + headers.push("content-type", body.type); } if (body && typeof body.read === "function") { body.read(0); @@ -6495,18 +6320,11 @@ var require_client_h1 = __commonJS({ process.emitWarning(new RequestContentLengthMismatchError()); } const socket = client[kSocket]; - clearIdleSocketValidation(socket); - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (request2.upgrade || request2.method === "CONNECT") { - util.destroy(socket, new InformationalError("aborted")); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - util.errorRequest(client, request2, error2 || new RequestAbortedError()); + util.errorRequest(client, request2, err || new RequestAbortedError()); util.destroy(body); util.destroy(socket, new InformationalError("aborted")); }; @@ -6862,7 +6680,6 @@ var require_client_h2 = __commonJS({ "node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { "use strict"; var assert = __require("node:assert"); - var { errorMonitor } = __require("node:events"); var { pipeline } = __require("node:stream"); var util = require_util(); var { @@ -6923,10 +6740,6 @@ var require_client_h2 = __commonJS({ } return result; } - function parseH2ResponseHeaders(headers) { - const { [HTTP2_HEADER_STATUS]: _statusCode, ...realHeaders } = headers; - return parseH2Headers(realHeaders); - } async function connectH2(client, socket) { client[kSocket] = socket; if (!h2ExperimentalWarned) { @@ -7090,22 +6903,16 @@ var require_client_h2 = __commonJS({ const { hostname, port } = client[kUrl]; headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ""}`; headers[HTTP2_HEADER_METHOD] = method; - const abort = (error2) => { - if (request2.aborted) { - return; - } - if (request2.completed) { - if (method === "CONNECT" && stream != null) { - util.destroy(stream, error2 || new RequestAbortedError()); - } + const abort = (err) => { + if (request2.aborted || request2.completed) { return; } - error2 = error2 || new RequestAbortedError(); - util.errorRequest(client, request2, error2); + err = err || new RequestAbortedError(); + util.errorRequest(client, request2, err); if (stream != null) { - util.destroy(stream, error2); + util.destroy(stream, err); } - util.destroy(body, error2); + util.destroy(body, err); client[kQueue][client[kRunningIdx]++] = null; client[kResume](); }; @@ -7120,42 +6927,18 @@ var require_client_h2 = __commonJS({ if (method === "CONNECT") { session.ref(); stream = session.request(headers, { endStream: false, signal }); - let upgradeResponseFinished = false; - const onResponse = (headers2) => { - upgradeResponseFinished = true; - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeResponse(Number(headers2[HTTP2_HEADER_STATUS]), headers2, parseH2ResponseHeaders); - }; - const onUpgradeError = (error2) => { - upgradeResponseFinished = true; - stream.off("response", onResponse); - request2.onUpgradeError(error2); - }; - const onReady = () => { - try { - request2.onUpgrade(null, null, stream); - } catch (error2) { - stream.off("response", onResponse); - abort(error2); - return; - } - if (request2.aborted) { - return; - } - stream.off("error", abort); - stream.once(errorMonitor, onUpgradeError); + if (stream.id && !stream.pending) { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; client[kQueue][client[kRunningIdx]++] = null; - }; - stream.once("response", onResponse); - stream.once("error", abort); - ++session[kOpenStreams]; - onReady(); + } else { + stream.once("ready", () => { + request2.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } stream.once("close", () => { - if (!upgradeResponseFinished && request2.completed) { - stream.off("response", onResponse); - stream.off(errorMonitor, onUpgradeError); - request2.onUpgradeError(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`)); - } session[kOpenStreams] -= 1; if (session[kOpenStreams] === 0) session.unref(); }); @@ -7716,10 +7499,9 @@ var require_client = __commonJS({ autoSelectFamilyAttemptTimeout, // h2 maxConcurrentStreams, - allowH2, - webSocket + allowH2 } = {}) { - super({ webSocket }); + super(); if (keepAlive !== void 0) { throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); } @@ -8225,8 +8007,8 @@ var require_pool_base = __commonJS({ var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); var kStats = /* @__PURE__ */ Symbol("stats"); var PoolBase = class extends DispatcherBase { - constructor(opts) { - super(opts); + constructor() { + super(); this[kQueue] = new FixedQueue(); this[kClients] = []; this[kQueued] = 0; @@ -8397,6 +8179,7 @@ var require_pool = __commonJS({ allowH2, ...options } = {}) { + super(); if (connections != null && (!Number.isFinite(connections) || connections < 0)) { throw new InvalidArgumentError("invalid connections"); } @@ -8417,7 +8200,6 @@ var require_pool = __commonJS({ ...connect }); } - super(options); this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; this[kConnections] = connections || null; this[kUrl] = util.parseOrigin(origin); @@ -8617,6 +8399,7 @@ var require_agent = __commonJS({ } var Agent = class extends DispatcherBase { constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + super(); if (typeof factory !== "function") { throw new InvalidArgumentError("factory must be a function."); } @@ -8626,7 +8409,6 @@ var require_agent = __commonJS({ if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { throw new InvalidArgumentError("maxRedirections must be a positive number"); } - super(options); if (connect && typeof connect !== "function") { connect = { ...connect }; } @@ -9067,24 +8849,6 @@ var require_retry_handler = __commonJS({ const current = Date.now(); return new Date(retryAfter).getTime() - current; } - function validatePartialResponseContentLength(headers, range, statusCode, retryCount) { - const contentLength = headers["content-length"]; - if (contentLength == null) { - return null; - } - if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) { - return null; - } - const length = Number(contentLength); - const expectedLength = range.end - range.start + 1; - if (!Number.isFinite(length) || length !== expectedLength) { - return new RequestRetryError("Content-Length mismatch", statusCode, { - headers, - data: { count: retryCount } - }); - } - return null; - } var RetryHandler = class _RetryHandler { constructor(opts, handlers) { const { retryOptions, ...dispatchOpts } = opts; @@ -9138,7 +8902,6 @@ var require_retry_handler = __commonJS({ this.end = null; this.etag = null; this.resume = null; - this.headersSent = false; this.handler.onConnect((reason) => { this.aborted = true; if (this.abort) { @@ -9148,17 +8911,6 @@ var require_retry_handler = __commonJS({ } }); } - checkpointResponseEnd(headers, resume) { - if (this.end == null && this.opts.method !== "HEAD") { - const contentLength = headers["content-length"]; - this.end = contentLength != null ? Number(contentLength) - 1 : null; - assert( - this.end == null || Number.isFinite(this.end), - "invalid content-length" - ); - } - this.resume = this.end != null ? resume : null; - } onRequestSent() { if (this.handler.onRequestSent) { this.handler.onRequestSent(); @@ -9220,9 +8972,7 @@ var require_retry_handler = __commonJS({ const headers = parseHeaders(rawHeaders); this.retryCount += 1; if (statusCode >= 300) { - if (!this.headersSent && this.retryOpts.statusCodes.includes(statusCode) === false) { - this.headersSent = true; - this.checkpointResponseEnd(headers, resume); + if (this.retryOpts.statusCodes.includes(statusCode) === false) { return this.handler.onHeaders( statusCode, rawHeaders, @@ -9271,21 +9021,9 @@ var require_retry_handler = __commonJS({ ); return false; } - const contentLengthError = validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = contentRange; - if (this.start !== start || this.end != null && this.end !== end) { - this.abort( - new RequestRetryError("Content-Range mismatch", statusCode, { - headers, - data: { count: this.retryCount } - }) - ); - return false; - } + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); this.resume = resume; return true; } @@ -9293,7 +9031,6 @@ var require_retry_handler = __commonJS({ if (statusCode === 206) { const range = parseRangeHeader(headers["content-range"]); if (range == null) { - this.headersSent = true; return this.handler.onHeaders( statusCode, rawHeaders, @@ -9301,11 +9038,6 @@ var require_retry_handler = __commonJS({ statusMessage ); } - const contentLengthError = validatePartialResponseContentLength(headers, range, statusCode, this.retryCount); - if (contentLengthError != null) { - this.abort(contentLengthError); - return false; - } const { start, size, end = size - 1 } = range; assert( start != null && Number.isFinite(start), @@ -9325,7 +9057,6 @@ var require_retry_handler = __commonJS({ "invalid content-length" ); this.resume = resume; - this.headersSent = true; this.etag = headers.etag != null ? headers.etag : null; if (this.etag != null && this.etag.startsWith("W/")) { this.etag = null; @@ -9353,7 +9084,7 @@ var require_retry_handler = __commonJS({ return this.handler.onComplete(rawTrailers); } onError(err) { - if (this.aborted || isDisturbed(this.opts.body) || this.headersSent && this.resume == null) { + if (this.aborted || isDisturbed(this.opts.body)) { return this.handler.onError(err); } if (this.retryCount - this.retryCountCheckpoint > 0) { @@ -16152,48 +15883,14 @@ var require_util6 = __commonJS({ for (let i = 0; i < path.length; ++i) { const code = path.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) - code > 126 || // exclude DEL and non-ascii + code === 127 || // DEL code === 59) { throw new Error("Invalid cookie path"); } } } - function isLetterOrDigit(code) { - return code >= 48 && code <= 57 || // 0-9 - code >= 65 && code <= 90 || // A-Z - code >= 97 && code <= 122; - } function validateCookieDomain(domain) { - if (domain === " ") { - return; - } - if (domain.length > 255) { - throw new Error("Invalid cookie domain"); - } - let labelLength = 0; - for (let i = 0; i < domain.length; ++i) { - const code = domain.charCodeAt(i); - if (code === 46) { - if (labelLength === 0) { - throw new Error("Invalid cookie domain"); - } - if (domain.charCodeAt(i - 1) === 45) { - throw new Error("Invalid cookie domain"); - } - labelLength = 0; - continue; - } - if (labelLength === 0 && !isLetterOrDigit(code)) { - throw new Error("Invalid cookie domain"); - } - if (!isLetterOrDigit(code) && code !== 45) { - throw new Error("Invalid cookie domain"); - } - if (++labelLength > 63) { - throw new Error("Invalid cookie domain"); - } - } - if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 45) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { throw new Error("Invalid cookie domain"); } } @@ -16276,11 +15973,7 @@ var require_util6 = __commonJS({ throw new Error("Invalid unparsed"); } const [key, ...value] = part.split("="); - const trimmedKey = key.trim(); - const joinedValue = value.join("="); - validateCookieName(trimmedKey); - validateCookieValue(joinedValue); - out.push(`${trimmedKey}=${joinedValue}`); + out.push(`${key.trim()}=${value.join("=")}`); } return out.join("; "); } @@ -16410,14 +16103,18 @@ var require_parse = __commonJS({ } else if (attributeNameLowercase === "httponly") { cookieAttributeList.httpOnly = true; } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; const attributeValueLowercase = attributeValue.toLowerCase(); - if (attributeValueLowercase === "none") { - cookieAttributeList.sameSite = "None"; - } else if (attributeValueLowercase === "strict") { - cookieAttributeList.sameSite = "Strict"; - } else if (attributeValueLowercase === "lax") { - cookieAttributeList.sameSite = "Lax"; + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; } + cookieAttributeList.sameSite = enforcement; } else { cookieAttributeList.unparsed ??= []; cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); @@ -17239,7 +16936,7 @@ var require_connection = __commonJS({ const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); if (secProtocol !== null) { const requestProtocols = getDecodeSplit("sec-websocket-protocol", request2.headersList); - if (requestProtocols === null || !requestProtocols.includes(secProtocol)) { + if (!requestProtocols.includes(secProtocol)) { failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); return; } @@ -17345,26 +17042,31 @@ var require_permessage_deflate = __commonJS({ var tail = Buffer.from([0, 0, 255, 255]); var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); var kLength = /* @__PURE__ */ Symbol("kLength"); + var kDefaultMaxDecompressedSize = 4 * 1024 * 1024; var PerMessageDeflate = class { /** @type {import('node:zlib').InflateRaw} */ #inflate; #options = {}; - #maxPayloadSize = 0; + /** @type {number} */ + #maxDecompressedSize; + /** @type {boolean} */ + #aborted = false; + /** @type {Function|null} */ + #currentCallback = null; /** * @param {Map} extensions + * @param {{ maxDecompressedMessageSize?: number }} [options] */ - constructor(extensions, options) { + constructor(extensions, options = {}) { this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); - this.#maxPayloadSize = options.maxPayloadSize; + this.#maxDecompressedSize = options.maxDecompressedMessageSize ?? kDefaultMaxDecompressedSize; } - /** - * Decompress a compressed payload. - * @param {Buffer} chunk Compressed data - * @param {boolean} fin Final fragment flag - * @param {Function} callback Callback function - */ decompress(chunk, fin, callback) { + if (this.#aborted) { + callback(new MessageSizeExceededError()); + return; + } if (!this.#inflate) { let windowBits = Z_DEFAULT_WINDOWBITS; if (this.#options.serverMaxWindowBits) { @@ -17383,12 +17085,20 @@ var require_permessage_deflate = __commonJS({ this.#inflate[kBuffer] = []; 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] > this.#maxDecompressedSize) { + 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); @@ -17398,17 +17108,19 @@ var require_permessage_deflate = __commonJS({ callback(err); }); } + 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; } 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); }); } @@ -17439,14 +17151,8 @@ var require_receiver = __commonJS({ var { WebsocketFrameSend } = require_frame(); var { closeWebSocketConnection } = require_connection(); var { PerMessageDeflate } = require_permessage_deflate(); - var { MessageSizeExceededError } = require_errors(); - function failWebsocketConnectionWithCode(ws, code, reason) { - closeWebSocketConnection(ws, code, reason, Buffer.byteLength(reason)); - failWebsocketConnection(ws, reason); - } var ByteParser = class extends Writable { #buffers = []; - #fragmentsBytes = 0; #byteOffset = 0; #loop = false; #state = parserStates.INFO; @@ -17454,21 +17160,18 @@ var require_receiver = __commonJS({ #fragments = []; /** @type {Map} */ #extensions; - /** @type {number} */ - #maxFragments; - /** @type {number} */ - #maxPayloadSize; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {import('./websocket').WebSocket} ws * @param {Map|null} extensions - * @param {{ maxFragments?: number, maxPayloadSize?: number }} [options] + * @param {{ maxDecompressedMessageSize?: number }} [options] */ constructor(ws, extensions, options = {}) { super(); this.ws = ws; this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; - this.#maxFragments = options.maxFragments ?? 0; - this.#maxPayloadSize = options.maxPayloadSize ?? 0; + this.#options = options; if (this.#extensions.has("permessage-deflate")) { this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); } @@ -17483,13 +17186,6 @@ var require_receiver = __commonJS({ this.#loop = true; 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, @@ -17549,9 +17245,6 @@ var require_receiver = __commonJS({ 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) { @@ -17572,9 +17265,6 @@ var require_receiver = __commonJS({ const buffer = this.consume(2); 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(); @@ -17588,9 +17278,6 @@ var require_receiver = __commonJS({ } 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(); @@ -17601,46 +17288,32 @@ var require_receiver = __commonJS({ 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 (!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, - (error2, data) => { - if (error2) { - const code = error2 instanceof MessageSizeExceededError ? 1009 : 1007; - failWebsocketConnectionWithCode(this.ws, code, error2.message); - return; - } - if (!this.writeFragments(data)) { - return; - } - if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { - failWebsocketConnectionWithCode(this.ws, 1009, new MessageSizeExceededError().message); - return; - } - if (!this.#info.fin) { - this.#state = parserStates.INFO; - this.#loop = true; - this.run(callback); - return; - } - websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); - this.#loop = true; + this.#extensions.get("permessage-deflate").decompress(body, this.#info.fin, (error2, data) => { + if (error2) { + failWebsocketConnection(this.ws, error2.message); + return; + } + this.#fragments.push(data); + if (!this.#info.fin) { this.#state = parserStates.INFO; + this.#loop = true; this.run(callback); + return; } - ); + 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; } @@ -17683,26 +17356,6 @@ var require_receiver = __commonJS({ this.#byteOffset -= n; 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); let code; @@ -17914,6 +17567,8 @@ var require_websocket = __commonJS({ #extensions = ""; /** @type {SendQueue} */ #sendQueue; + /** @type {{ maxDecompressedMessageSize?: number }} */ + #options; /** * @param {string} url * @param {string|string[]} protocols @@ -17957,6 +17612,9 @@ var require_websocket = __commonJS({ throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); } this[kWebSocketURL] = new URL(urlRecord.href); + this.#options = { + maxDecompressedMessageSize: options.maxDecompressedMessageSize + }; const client = environmentSettingsObject.settingsObject; this[kController] = establishWebSocketConnection( urlRecord, @@ -18140,13 +17798,7 @@ var require_websocket = __commonJS({ */ #onConnectionEstablished(response, parsedExtensions) { 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, this.#options); parser.on("drain", onParserDrain); parser.on("error", onParserError.bind(this)); response.socket.ws = this; @@ -18221,6 +17873,19 @@ var require_websocket = __commonJS({ { key: "headers", converter: webidl.nullableConverter(webidl.converters.HeadersInit) + }, + { + key: "maxDecompressedMessageSize", + converter: webidl.nullableConverter((V) => { + V = webidl.converters["unsigned long long"](V); + if (V <= 0) { + throw webidl.errors.exception({ + header: "WebSocket constructor", + message: "maxDecompressedMessageSize must be greater than 0" + }); + } + return V; + }) } ]); webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { @@ -18299,40 +17964,6 @@ var require_eventsource_stream = __commonJS({ var CR = 13; var COLON = 58; var SPACE = 32; - var DATA = Buffer.from("data"); - var EVENT = Buffer.from("event"); - var ID = Buffer.from("id"); - var RETRY = Buffer.from("retry"); - function isASCIINumberBytes(buffer, start) { - if (start >= buffer.length) { - return false; - } - for (let i = start; i < buffer.length; i++) { - if (buffer[i] < 48 || buffer[i] > 57) { - return false; - } - } - return true; - } - function isValidLastEventIdBytes(buffer, start) { - for (let i = start; i < buffer.length; i++) { - if (buffer[i] === 0) { - return false; - } - } - return true; - } - function isFieldName(line, length, field) { - if (length !== field.length) { - return false; - } - for (let i = 0; i < length; i++) { - if (line[i] !== field[i]) { - return false; - } - } - return true; - } var EventSourceStream = class extends Transform { /** * @type {eventSourceSettings} @@ -18352,13 +17983,10 @@ var require_eventsource_stream = __commonJS({ */ eventEndCheck = false; /** - * @type {Buffer[]} + * @type {Buffer} */ - chunks = []; - chunkIndex = 0; + buffer = null; pos = 0; - lineChunkIndex = 0; - linePos = 0; event = { data: void 0, event: void 0, @@ -18389,30 +18017,63 @@ var require_eventsource_stream = __commonJS({ callback(); return; } - this.chunks.push(chunk); + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } if (this.checkBOM) { - if (this.handleBOM()) { - callback(); - return; + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; } } - while (this.hasCurrentByte()) { - const byte = this.currentByte(); + while (this.pos < this.buffer.length) { if (this.eventEndCheck) { if (this.crlfCheck) { - if (byte === LF) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.crlfCheck = false; - this.consumeCurrentByte(); continue; } this.crlfCheck = false; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.consumeCurrentByte(); - if (this.hasPendingEvent()) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { this.processEvent(this.event); } this.clearEvent(); @@ -18421,16 +18082,17 @@ var require_eventsource_stream = __commonJS({ this.eventEndCheck = false; continue; } - if (byte === LF || byte === CR) { - if (byte === CR) { + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { this.crlfCheck = true; } - this.parseLine(this.readLine(), this.event); - this.consumeCurrentByte(); + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; this.eventEndCheck = true; continue; } - this.advanceCursor(); + this.pos++; } callback(); } @@ -18446,42 +18108,43 @@ var require_eventsource_stream = __commonJS({ if (colonPosition === 0) { return; } - let fieldLength = line.length; - let valueStart = line.length; + let field = ""; + let value = ""; if (colonPosition !== -1) { - fieldLength = colonPosition; - valueStart = colonPosition + 1; + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; if (line[valueStart] === SPACE) { ++valueStart; } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; } - if (isFieldName(line, fieldLength, DATA)) { - const value = line.toString("utf8", valueStart); - if (event.data === void 0) { - event.data = value; - } else { - event.data += ` + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` ${value}`; - } - return; - } - if (isFieldName(line, fieldLength, RETRY)) { - if (isASCIINumberBytes(line, valueStart)) { - event.retry = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, ID)) { - if (isValidLastEventIdBytes(line, valueStart)) { - event.id = line.toString("utf8", valueStart); - } - return; - } - if (isFieldName(line, fieldLength, EVENT)) { - const value = line.toString("utf8", valueStart); - if (value.length > 0) { - event.event = value; - } + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; } } /** @@ -18506,120 +18169,12 @@ ${value}`; } } clearEvent() { - this.event.data = void 0; - this.event.event = void 0; - this.event.id = void 0; - this.event.retry = void 0; - } - hasPendingEvent() { - return this.event.data !== void 0 || this.event.event !== void 0 || this.event.id !== void 0 || this.event.retry !== void 0; - } - hasCurrentByte() { - return this.chunkIndex < this.chunks.length && this.pos < this.chunks[this.chunkIndex].length; - } - currentByte() { - return this.chunks[this.chunkIndex][this.pos]; - } - consumeCurrentByte() { - this.advanceCursor(); - this.syncLineStartToCursor(); - } - advanceCursor() { - this.pos++; - while (this.chunkIndex < this.chunks.length && this.pos >= this.chunks[this.chunkIndex].length) { - this.chunkIndex++; - this.pos = 0; - } - } - syncLineStartToCursor() { - this.lineChunkIndex = this.chunkIndex; - this.linePos = this.pos; - this.dropConsumedChunks(); - } - dropConsumedChunks() { - while (this.lineChunkIndex > 0) { - this.chunks.shift(); - this.lineChunkIndex--; - this.chunkIndex--; - } - if (this.chunkIndex === this.chunks.length) { - this.chunks.length = 0; - this.chunkIndex = 0; - this.pos = 0; - this.lineChunkIndex = 0; - this.linePos = 0; - } - } - readLine() { - if (this.lineChunkIndex === this.chunkIndex) { - return this.chunks[this.chunkIndex].subarray(this.linePos, this.pos); - } - const chunks = []; - let length = 0; - for (let i = this.lineChunkIndex; i <= this.chunkIndex; i++) { - const chunk = this.chunks[i]; - const start = i === this.lineChunkIndex ? this.linePos : 0; - const end = i === this.chunkIndex ? this.pos : chunk.length; - const slice = chunk.subarray(start, end); - length += slice.length; - chunks.push(slice); - } - return Buffer.concat(chunks, length); - } - peekBufferedByte(offset) { - let chunkIndex = this.lineChunkIndex; - let pos = this.linePos; - while (chunkIndex < this.chunks.length) { - const chunk = this.chunks[chunkIndex]; - const remaining = chunk.length - pos; - if (offset < remaining) { - return chunk[pos + offset]; - } - offset -= remaining; - chunkIndex++; - pos = 0; - } - } - discardLeadingBytes(count) { - while (count > 0 && this.lineChunkIndex < this.chunks.length) { - const chunk = this.chunks[this.lineChunkIndex]; - const remaining = chunk.length - this.linePos; - if (count < remaining) { - this.linePos += count; - count = 0; - } else { - count -= remaining; - this.lineChunkIndex++; - this.linePos = 0; - } - } - this.chunkIndex = this.lineChunkIndex; - this.pos = this.linePos; - this.dropConsumedChunks(); - } - handleBOM() { - const first = this.peekBufferedByte(0); - const second = this.peekBufferedByte(1); - const third = this.peekBufferedByte(2); - if (second === void 0) { - if (first === BOM[0]) { - return true; - } - this.checkBOM = false; - return true; - } - if (third === void 0) { - if (first === BOM[0] && second === BOM[1]) { - return true; - } - this.checkBOM = false; - return false; - } - if (first === BOM[0] && second === BOM[1] && third === BOM[2]) { - this.discardLeadingBytes(3); - } - this.checkBOM = false; - return !this.hasCurrentByte(); + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; } }; module.exports = { diff --git a/__mocks__/react-native-onyx.ts b/__mocks__/react-native-onyx.ts index 6db22ac1b627..f5b09f2949da 100644 --- a/__mocks__/react-native-onyx.ts +++ b/__mocks__/react-native-onyx.ts @@ -5,7 +5,7 @@ import type {ConnectOptions, OnyxKey} from 'react-native-onyx'; // eslint-disable-next-line no-restricted-imports -import Onyx, {useOnyx} from 'react-native-onyx'; +import Onyx, {useOnyx, useOnyxState} from 'react-native-onyx'; let connectCallbackDelay = 0; function addDelayToConnectCallback(delay: number) { @@ -41,4 +41,4 @@ const reactNativeOnyxMock: ReactNativeOnyxMock = { export default reactNativeOnyxMock; -export {useOnyx}; +export {useOnyx, useOnyxState}; diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 9aceaf15c17e..bf6671bf9e52 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1439,7 +1439,6 @@ const ONYXKEYS = { VISIBLE_REPORT_ACTIONS: 'visibleReportActions', NON_PERSONAL_AND_WORKSPACE_CARD_LIST: 'nonPersonalAndWorkspaceCardList', PERSONAL_AND_WORKSPACE_CARD_LIST: 'personalAndWorkspaceCardList', - CARD_FEED_ERRORS: 'cardFeedErrors', RAM_ONLY_SORTED_REPORT_ACTIONS: 'sortedReportActions', LOGIN_TO_ACCOUNT_ID_MAP: 'loginToAccountIDMap', GUIDE_ACCOUNT_IDS: 'guideAccountIDs', @@ -2022,7 +2021,6 @@ type OnyxDerivedValuesMapping = { [ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS]: OnyxTypes.VisibleReportActionsDerivedValue; [ONYXKEYS.DERIVED.NON_PERSONAL_AND_WORKSPACE_CARD_LIST]: OnyxTypes.NonPersonalAndWorkspaceCardListDerivedValue; [ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST]: OnyxTypes.PersonalAndWorkspaceCardListDerivedValue; - [ONYXKEYS.DERIVED.CARD_FEED_ERRORS]: OnyxTypes.CardFeedErrorsDerivedValue; [ONYXKEYS.DERIVED.RAM_ONLY_SORTED_REPORT_ACTIONS]: OnyxTypes.SortedReportActionsDerivedValue; [ONYXKEYS.DERIVED.LOGIN_TO_ACCOUNT_ID_MAP]: OnyxTypes.LoginToAccountIDMapDerivedValue; [ONYXKEYS.DERIVED.SPEND_DATA_SIGNATURE]: OnyxTypes.SpendDataSignatureDerivedValue; diff --git a/src/components/Table/TableBody.tsx b/src/components/Table/TableBody.tsx index 9a4db2f7aead..faa96b4da20f 100644 --- a/src/components/Table/TableBody.tsx +++ b/src/components/Table/TableBody.tsx @@ -164,6 +164,7 @@ function TableBodyList({contentContainerStyle, emptyMessage, onLayout, style, .. noResultsStateElement, tableListMetadata, isEmptyResult, + isDefaultViewEmpty, scrollWidth, tableWidth, } = useTableContext(); @@ -337,8 +338,10 @@ function TableBodyList({contentContainerStyle, emptyMessage, onLayout, style, .. ); - const emptyStateContent = - tableListMetadata.hasPageHeader && isEmptyResult ? (noResultsStateElement ?? EmptyResultComponent) : (emptyStateElement ?? renderListComponent(ListEmptyComponent)); + // When the default view hides every row (e.g. all workspaces are archived), no search or filter is active, + // so show the empty state rather than "No results". + const shouldShowNoResultsState = tableListMetadata.hasPageHeader && isEmptyResult && !isDefaultViewEmpty; + const emptyStateContent = shouldShowNoResultsState ? (noResultsStateElement ?? EmptyResultComponent) : (emptyStateElement ?? renderListComponent(ListEmptyComponent)); const footerElement = renderListComponent(ListFooterComponent); // Consumer footer flex growth is useful below normal rows, but inside the combined empty-state // footer it can expand over the page header. Preserve the remaining style while disabling growth. diff --git a/src/components/Table/TableEmptyStates/TableNoResultsState.tsx b/src/components/Table/TableEmptyStates/TableNoResultsState.tsx index 60a93ca4a2c6..30c49a66fe35 100644 --- a/src/components/Table/TableEmptyStates/TableNoResultsState.tsx +++ b/src/components/Table/TableEmptyStates/TableNoResultsState.tsx @@ -21,10 +21,11 @@ type TableNoResultsStateProps = Omit (cardFeedErrors: OnyxEntry) => - !!cardFeedErrors?.shouldShowRbrForWorkspaceAccountID?.[workspaceAccountID]; +const createCardFeedErrorsSelector = (workspaceAccountID: number) => (cardFeedErrors: CardFeedErrors) => !!cardFeedErrors.shouldShowRbrForWorkspaceAccountID[workspaceAccountID]; const createPolicyErrorsSelector = (connectionSyncProgress: OnyxEntry) => (policy: OnyxEntry) => getUberConnectionErrorDirectlyFromPolicy(policy) || @@ -51,7 +51,7 @@ function WorkspaceRowBrickRoadIndicator({policyID}: WorkspaceRowBrickRoadIndicat const icons = useMemoizedLazyExpensifyIcons(['DotIndicator']); const workspaceAccountID = useWorkspaceAccountID(policyID); const [hasReimbursementAccountErrors] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {selector: hasReimbursementAccountErrorsSelector}); - const [hasCardFeedErrors] = useOnyx(ONYXKEYS.DERIVED.CARD_FEED_ERRORS, {selector: createCardFeedErrorsSelector(workspaceAccountID)}); + const hasCardFeedErrors = useCardFeedErrors(createCardFeedErrorsSelector(workspaceAccountID)); const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`); const [hasPolicyErrors] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {selector: createPolicyErrorsSelector(connectionSyncProgress)}); const [isHRCompleteSetupNeeded] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {selector: isMergeHRCompleteSetupNeededSelector}); diff --git a/src/hooks/useCardFeedErrors.ts b/src/hooks/useCardFeedErrors.ts index 9a7a3b6a85ca..7feaaeb0fb88 100644 --- a/src/hooks/useCardFeedErrors.ts +++ b/src/hooks/useCardFeedErrors.ts @@ -1,33 +1,29 @@ import ONYXKEYS from '@src/ONYXKEYS'; -import type {CardFeedErrors, CardFeedErrorState} from '@src/types/onyx/DerivedValues'; +import type {CardFeeds, WorkspaceCardsList} from '@src/types/onyx'; +import type {CardFeedErrors} from '@src/types/onyx/DerivedValues'; -import useOnyx from './useOnyx'; +import type {OnyxCollection} from 'react-native-onyx'; -const DEFAULT_CARD_FEED_ERROR_STATE: CardFeedErrorState = { - shouldShowRBR: false, - isFeedConnectionBroken: false, - shouldPromptBrokenConnection: false, - hasFeedErrors: false, - hasWorkspaceErrors: false, - hasFeedConnectionIssue: false, -}; +import {getCardFeedErrors} from '@selectors/CardFeedErrors'; +import {useOnyxState} from 'react-native-onyx'; -const DEFAULT_CARD_FEED_ERRORS: CardFeedErrors = { - cardFeedErrors: {}, - cardsWithBrokenFeedConnection: {}, - personalCardsWithBrokenConnection: {}, - shouldShowRbrForWorkspaceAccountID: {}, - shouldShowRbrForFeedNameWithDomainID: {}, - all: DEFAULT_CARD_FEED_ERROR_STATE, - companyCards: DEFAULT_CARD_FEED_ERROR_STATE, - expensifyCard: DEFAULT_CARD_FEED_ERROR_STATE, - personalCard: DEFAULT_CARD_FEED_ERROR_STATE, -}; +const CARD_FEED_ERRORS_DEPENDENCIES = [ONYXKEYS.CARD_LIST, ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER, ONYXKEYS.CURRENT_DATE]; -function useCardFeedErrors(): CardFeedErrors { - const [cardFeedErrors] = useOnyx(ONYXKEYS.DERIVED.CARD_FEED_ERRORS); - - return cardFeedErrors ?? DEFAULT_CARD_FEED_ERRORS; +function useCardFeedErrors(): CardFeedErrors; +function useCardFeedErrors(selector: (cardFeedErrors: CardFeedErrors) => TSelected): TSelected; +function useCardFeedErrors(selector?: (cardFeedErrors: CardFeedErrors) => TSelected): CardFeedErrors | TSelected { + return useOnyxState( + (state) => { + // useOnyxState's state view types a collection key as one member, but at runtime it returns the whole collection + /* eslint-disable @typescript-eslint/no-unsafe-type-assertion */ + const allWorkspaceCards = state[ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST] as OnyxCollection; + const cardFeeds = state[ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER] as OnyxCollection; + /* eslint-enable @typescript-eslint/no-unsafe-type-assertion */ + const cardFeedErrors = getCardFeedErrors(state[ONYXKEYS.CARD_LIST], allWorkspaceCards, cardFeeds, state[ONYXKEYS.CURRENT_DATE]); + return selector ? selector(cardFeedErrors) : cardFeedErrors; + }, + {dependencies: CARD_FEED_ERRORS_DEPENDENCIES}, + ); } export default useCardFeedErrors; diff --git a/src/libs/actions/OnyxDerived/ONYX_DERIVED_VALUES.ts b/src/libs/actions/OnyxDerived/ONYX_DERIVED_VALUES.ts index 4ea4fabd9560..9a7e58df26e3 100644 --- a/src/libs/actions/OnyxDerived/ONYX_DERIVED_VALUES.ts +++ b/src/libs/actions/OnyxDerived/ONYX_DERIVED_VALUES.ts @@ -4,7 +4,6 @@ import type {ValueOf} from 'type-fest'; import type {OnyxDerivedValueConfig} from './types'; -import cardFeedErrorsConfig from './configs/cardFeedErrors'; import guideAccountIDsConfig from './configs/guideAccountIDs'; import loginToAccountIDMapConfig from './configs/loginToAccountIDMap'; import nonPersonalAndWorkspaceCardListConfig from './configs/nonPersonalAndWorkspaceCardList'; @@ -28,7 +27,6 @@ const ONYX_DERIVED_VALUES = { [ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS]: visibleReportActionsConfig, [ONYXKEYS.DERIVED.NON_PERSONAL_AND_WORKSPACE_CARD_LIST]: nonPersonalAndWorkspaceCardListConfig, [ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST]: personalAndWorkspaceCardListConfig, - [ONYXKEYS.DERIVED.CARD_FEED_ERRORS]: cardFeedErrorsConfig, [ONYXKEYS.DERIVED.RAM_ONLY_SORTED_REPORT_ACTIONS]: sortedReportActionsConfig, [ONYXKEYS.DERIVED.LOGIN_TO_ACCOUNT_ID_MAP]: loginToAccountIDMapConfig, [ONYXKEYS.DERIVED.GUIDE_ACCOUNT_IDS]: guideAccountIDsConfig, diff --git a/src/libs/actions/OnyxDerived/configs/cardFeedErrors.ts b/src/libs/actions/OnyxDerived/configs/cardFeedErrors.ts deleted file mode 100644 index 787ee47c404e..000000000000 --- a/src/libs/actions/OnyxDerived/configs/cardFeedErrors.ts +++ /dev/null @@ -1,248 +0,0 @@ -import {getCombinedCardFeedsFromAllFeeds, getWorkspaceCardFeedsStatus} from '@libs/CardFeedUtils'; -import { - filterAllInactiveCards, - forEachAssignedCard, - getCardFeedWithDomainID, - isBrokenConnectionPastDismissThreshold, - hasCardConnectionIssue, - isCardConnectionBroken, - isLastScrapePastDismissThreshold, - isPersonalCard, -} from '@libs/CardUtils'; - -import createOnyxDerivedValueConfig from '@userActions/OnyxDerived/createOnyxDerivedValueConfig'; - -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type {Card} from '@src/types/onyx'; -import type {CardErrors, CardFeedErrorsObject, CardFeedErrorState} from '@src/types/onyx/DerivedValues'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; - -import {buildFeedKeysWithAssignedCards} from '@selectors/Card'; - -const DEFAULT_CARD_FEED_ERROR_STATE: CardFeedErrorState = { - shouldShowRBR: false, - hasFeedErrors: false, - hasWorkspaceErrors: false, - isFeedConnectionBroken: false, - shouldPromptBrokenConnection: false, - hasFeedConnectionIssue: false, -}; - -function getShouldShowRBR(state: Partial): boolean { - if (state.hasFeedErrors) { - return true; - } - if (state.hasWorkspaceErrors) { - return true; - } - - // Deliberately keyed on the prompting flag, not `isFeedConnectionBroken`: past the grace period we stop showing - // the RBR while the connection stays broken so it can still be fixed. - return !!state.shouldPromptBrokenConnection; -} - -export default createOnyxDerivedValueConfig({ - key: ONYXKEYS.DERIVED.CARD_FEED_ERRORS, - // CURRENT_DATE (day-granularity) is a trigger-only dependency: it makes this value recompute when the day rolls over so the - // 90-day broken-connection grace period (isBrokenConnectionPastDismissThreshold) is re-evaluated even if no card/feed data changes. - dependencies: [ONYXKEYS.CARD_LIST, ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER, ONYXKEYS.CURRENT_DATE], - compute: ([globalCardList, allWorkspaceCards, cardFeeds]) => { - const feedKeysWithCards = buildFeedKeysWithAssignedCards(allWorkspaceCards); - const combinedCompanyCardFeeds = getCombinedCardFeedsFromAllFeeds(cardFeeds, undefined, feedKeysWithCards); - const workspaceCardFeedsStatus = getWorkspaceCardFeedsStatus(cardFeeds); - - const cardFeedErrors: CardFeedErrorsObject = {}; - const shouldShowRbrForWorkspaceAccountID: Record = {}; - const shouldShowRbrForFeedNameWithDomainID: Record = {}; - - const allFeedsState: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; - const companyCardFeedsState: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; - const expensifyCardFeedStates: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; - const personalCardStates: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; - - const cardsWithBrokenFeedConnection: Record = {}; - const personalCardsWithBrokenConnection: Record = {}; - - function addErrorsForPersonalCard(card: Card) { - // Once the card has gone without a successful sync past the grace period we stop leading the user to it: the - // time-sensitive task and the RBR are removed. The connection error is a server-set `card.errors` entry, which - // is what lights the Account button via `hasPaymentMethodError`, so past the threshold it must not light the - // RBR. This is keyed on the last successful sync rather than `isCardConnectionBroken`, because the server sets - // the connection error even for scrape statuses that check ignores (e.g. 434). `errorFields` entries are left - // alone: they are written by a user-initiated action that failed (a manual sync, a reimbursable/start-date - // update), so they stay actionable no matter how old the connection is. The error itself stays on the card. - const isPastDismissThreshold = isLastScrapePastDismissThreshold(card); - const hasCardErrors = (!isPastDismissThreshold && !isEmptyObject(card.errors)) || !isEmptyObject(card.errorFields); - const cardErrors = { - ...(hasCardErrors - ? { - [card.cardID]: { - errors: card.errors, - errorFields: card.errorFields, - pendingAction: card.pendingAction, - }, - } - : {}), - } as Record; - - const isFeedConnectionBroken = hasCardConnectionIssue(card) && !isPastDismissThreshold; - // Track personal cards with broken feed connection - if (isFeedConnectionBroken) { - personalCardsWithBrokenConnection[card.cardID] = card; - } - const newFeedState: Omit = { - isFeedConnectionBroken, - // A personal card is fixed from its own details page, which reads the card directly, so there is no - // separate capability signal to preserve here. Prompting follows the same grace period. - shouldPromptBrokenConnection: isFeedConnectionBroken, - hasFeedErrors: !isEmptyObject(cardErrors), - hasWorkspaceErrors: false, - hasFeedConnectionIssue: hasCardConnectionIssue(card), - }; - const shouldShowRBR = getShouldShowRBR(newFeedState); - - personalCardStates.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken; - personalCardStates.shouldPromptBrokenConnection ||= newFeedState.shouldPromptBrokenConnection; - personalCardStates.hasFeedErrors ||= newFeedState.hasFeedErrors; - personalCardStates.shouldShowRBR ||= shouldShowRBR; - } - - function addErrorsForCard(card: Card) { - const bankName = card.bank; - const workspaceAccountID = Number(card.fundID); - - const isExpensifyCard = bankName === CONST.EXPENSIFY_CARD.BANK; - - if (Number.isNaN(workspaceAccountID)) { - return; - } - - const feedNameWithDomainID = getCardFeedWithDomainID(bankName, workspaceAccountID); - const previousFeedErrors = cardFeedErrors[feedNameWithDomainID] ?? DEFAULT_CARD_FEED_ERROR_STATE; - - const feed = combinedCompanyCardFeeds?.[feedNameWithDomainID]; - const feedErrors = { - ...previousFeedErrors.feedErrors, - ...feed?.errors, - } as Errors; - const hasFeedErrors = feedNameWithDomainID ? !isEmptyObject(feedErrors) : false; - - const workspaceErrors = workspaceCardFeedsStatus?.[workspaceAccountID]?.errors; - const hasWorkspaceErrors = !!workspaceErrors; - - const hasCardErrors = !isEmptyObject(card.errors) || !isEmptyObject(card.errorFields) || card.pendingAction; - const cardErrors = { - ...previousFeedErrors.cardErrors, - ...(cardFeedErrors[feedNameWithDomainID]?.cardErrors ?? {}), - ...(hasCardErrors - ? { - [card.cardID]: { - errors: card.errors, - errorFields: card.errorFields, - pendingAction: card.pendingAction, - }, - } - : {}), - } as Record; - - // Keep the broken state itself truthful: the Company cards page renders its "log into your bank" fix from - // this flag, and the reconnect needs it to clear the error afterwards. Only stop *prompting* (the RBR and - // the time-sensitive task) once the connection has been unresolved past the grace period. - const isFeedConnectionBroken = isCardConnectionBroken(card); - const shouldPromptBrokenConnection = isFeedConnectionBroken && !isBrokenConnectionPastDismissThreshold(card); - - const newFeedState: Omit = { - isFeedConnectionBroken: isFeedConnectionBroken || previousFeedErrors.isFeedConnectionBroken, - shouldPromptBrokenConnection: shouldPromptBrokenConnection || previousFeedErrors.shouldPromptBrokenConnection, - hasFeedErrors: hasFeedErrors || previousFeedErrors.hasFeedErrors, - hasWorkspaceErrors: hasWorkspaceErrors || previousFeedErrors.hasWorkspaceErrors, - hasFeedConnectionIssue: hasCardConnectionIssue(card) || previousFeedErrors.hasFeedConnectionIssue, - }; - - const shouldShowRBR = getShouldShowRBR(newFeedState) || previousFeedErrors.shouldShowRBR; - - cardFeedErrors[feedNameWithDomainID] = { - ...newFeedState, - shouldShowRBR, - cardErrors, - feedErrors, - workspaceErrors, - }; - - // Track cards with broken feed connection. This stays truthful past the grace period so that reconnecting - // still clears the error (see useUpdateFeedBrokenConnection); consumers that prompt the user filter on the - // grace period themselves. - if (isFeedConnectionBroken) { - cardsWithBrokenFeedConnection[card.cardID] = card; - } - - // Update aggregate states - once true, always stays true - const cardTypeState = isExpensifyCard ? expensifyCardFeedStates : companyCardFeedsState; - - allFeedsState.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken; - allFeedsState.shouldPromptBrokenConnection ||= newFeedState.shouldPromptBrokenConnection; - allFeedsState.hasFeedErrors ||= newFeedState.hasFeedErrors; - allFeedsState.hasWorkspaceErrors ||= newFeedState.hasWorkspaceErrors; - allFeedsState.hasFeedConnectionIssue ||= newFeedState.hasFeedConnectionIssue; - - cardTypeState.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken; - cardTypeState.shouldPromptBrokenConnection ||= newFeedState.shouldPromptBrokenConnection; - cardTypeState.hasFeedErrors ||= newFeedState.hasFeedErrors; - cardTypeState.hasWorkspaceErrors ||= newFeedState.hasWorkspaceErrors; - cardTypeState.hasFeedConnectionIssue ||= newFeedState.hasFeedConnectionIssue; - - shouldShowRbrForWorkspaceAccountID[workspaceAccountID] ||= shouldShowRBR; - shouldShowRbrForFeedNameWithDomainID[feedNameWithDomainID] ||= shouldShowRBR; - } - - for (const card of Object.values(globalCardList ?? {})) { - const isPersonal = isPersonalCard(card); - if (isPersonal) { - addErrorsForPersonalCard(card); - } else { - addErrorsForCard(card); - } - } - - const workspaceCards = allWorkspaceCards ?? {}; - for (const key of Object.keys(workspaceCards)) { - const keyParts = key.split(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST); - const workspaceCardParamParts = keyParts.at(1)?.split('_'); - - if (!workspaceCardParamParts) { - continue; - } - - forEachAssignedCard(filterAllInactiveCards(workspaceCards[key]), addErrorsForCard); - } - - allFeedsState.shouldShowRBR = getShouldShowRBR(allFeedsState); - companyCardFeedsState.shouldShowRBR = getShouldShowRBR(companyCardFeedsState); - expensifyCardFeedStates.shouldShowRBR = getShouldShowRBR(expensifyCardFeedStates); - - return { - // The errors of all card feeds. - cardFeedErrors, - cardsWithBrokenFeedConnection, - personalCardsWithBrokenConnection, - - // Mappings of whether to show the RBR for each workspace account ID and per feed name with domain ID - shouldShowRbrForWorkspaceAccountID, - shouldShowRbrForFeedNameWithDomainID, - - // Whether any of the feeds have one of the below errors - all: allFeedsState, - - // Whether any of the company cards have one of the below errors - companyCards: companyCardFeedsState, - - // Whether any of the expensify cards have one of the below errors - expensifyCard: expensifyCardFeedStates, - - // Whether any of the personal cards have one of the below errors - personalCard: personalCardStates, - }; - }, -}); diff --git a/src/pages/home/YourSpendSection/useYourSpendData.ts b/src/pages/home/YourSpendSection/useYourSpendData.ts index 91fead4efa12..896107a5c1a3 100644 --- a/src/pages/home/YourSpendSection/useYourSpendData.ts +++ b/src/pages/home/YourSpendSection/useYourSpendData.ts @@ -434,7 +434,7 @@ function useYourSpendData(): UseYourSpendDataReturn { ); // Destructure here so downstream memos depend only on the sub-records, not on - // the parent value that's rebuilt on every CARD_FEED_ERRORS tick. + // the parent value that's rebuilt whenever a card input changes. const {cardsWithBrokenFeedConnection, personalCardsWithBrokenConnection} = useCardFeedErrors(); // Memo anchor: the compiler does not auto-cache these calls, so downstream diff --git a/src/selectors/CardFeedErrors.ts b/src/selectors/CardFeedErrors.ts new file mode 100644 index 000000000000..a7a62731ffc5 --- /dev/null +++ b/src/selectors/CardFeedErrors.ts @@ -0,0 +1,279 @@ +import {getCombinedCardFeedsFromAllFeeds, getWorkspaceCardFeedsStatus} from '@libs/CardFeedUtils'; +import { + filterAllInactiveCards, + forEachAssignedCard, + getCardFeedWithDomainID, + isBrokenConnectionPastDismissThreshold, + hasCardConnectionIssue, + isCardConnectionBroken, + isLastScrapePastDismissThreshold, + isPersonalCard, +} from '@libs/CardUtils'; + +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Card, CardFeeds, CardList, WorkspaceCardsList} from '@src/types/onyx'; +import type {CardErrors, CardFeedErrors, CardFeedErrorsObject, CardFeedErrorState} from '@src/types/onyx/DerivedValues'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; + +import {buildFeedKeysWithAssignedCards} from './Card'; + +const DEFAULT_CARD_FEED_ERROR_STATE: CardFeedErrorState = { + shouldShowRBR: false, + hasFeedErrors: false, + hasWorkspaceErrors: false, + isFeedConnectionBroken: false, + shouldPromptBrokenConnection: false, + hasFeedConnectionIssue: false, +}; + +function getShouldShowRBR(state: Partial): boolean { + if (state.hasFeedErrors) { + return true; + } + if (state.hasWorkspaceErrors) { + return true; + } + + // Deliberately keyed on the prompting flag, not `isFeedConnectionBroken`: past the grace period we stop showing + // the RBR while the connection stays broken so it can still be fixed. + return !!state.shouldPromptBrokenConnection; +} + +/** Builds the errors of every card feed, workspace and personal card from the card list, the workspace cards and the domain feeds. */ +function computeCardFeedErrors(globalCardList: OnyxEntry, allWorkspaceCards: OnyxCollection, cardFeeds: OnyxCollection): CardFeedErrors { + const feedKeysWithCards = buildFeedKeysWithAssignedCards(allWorkspaceCards); + const combinedCompanyCardFeeds = getCombinedCardFeedsFromAllFeeds(cardFeeds, undefined, feedKeysWithCards); + const workspaceCardFeedsStatus = getWorkspaceCardFeedsStatus(cardFeeds); + + const cardFeedErrors: CardFeedErrorsObject = {}; + const shouldShowRbrForWorkspaceAccountID: Record = {}; + const shouldShowRbrForFeedNameWithDomainID: Record = {}; + + const allFeedsState: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; + const companyCardFeedsState: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; + const expensifyCardFeedStates: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; + const personalCardStates: CardFeedErrorState = {...DEFAULT_CARD_FEED_ERROR_STATE}; + + const cardsWithBrokenFeedConnection: Record = {}; + const personalCardsWithBrokenConnection: Record = {}; + + function addErrorsForPersonalCard(card: Card) { + // Once the card has gone without a successful sync past the grace period we stop leading the user to it: the + // time-sensitive task and the RBR are removed. The connection error is a server-set `card.errors` entry, which + // is what lights the Account button via `hasPaymentMethodError`, so past the threshold it must not light the + // RBR. This is keyed on the last successful sync rather than `isCardConnectionBroken`, because the server sets + // the connection error even for scrape statuses that check ignores (e.g. 434). `errorFields` entries are left + // alone: they are written by a user-initiated action that failed (a manual sync, a reimbursable/start-date + // update), so they stay actionable no matter how old the connection is. The error itself stays on the card. + const isPastDismissThreshold = isLastScrapePastDismissThreshold(card); + const hasCardErrors = (!isPastDismissThreshold && !isEmptyObject(card.errors)) || !isEmptyObject(card.errorFields); + const cardErrors = { + ...(hasCardErrors + ? { + [card.cardID]: { + errors: card.errors, + errorFields: card.errorFields, + pendingAction: card.pendingAction, + }, + } + : {}), + } as Record; + + const isFeedConnectionBroken = hasCardConnectionIssue(card) && !isPastDismissThreshold; + // Track personal cards with broken feed connection + if (isFeedConnectionBroken) { + personalCardsWithBrokenConnection[card.cardID] = card; + } + const newFeedState: Omit = { + isFeedConnectionBroken, + // A personal card is fixed from its own details page, which reads the card directly, so there is no + // separate capability signal to preserve here. Prompting follows the same grace period. + shouldPromptBrokenConnection: isFeedConnectionBroken, + hasFeedErrors: !isEmptyObject(cardErrors), + hasWorkspaceErrors: false, + hasFeedConnectionIssue: hasCardConnectionIssue(card), + }; + const shouldShowRBR = getShouldShowRBR(newFeedState); + + personalCardStates.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken; + personalCardStates.shouldPromptBrokenConnection ||= newFeedState.shouldPromptBrokenConnection; + personalCardStates.hasFeedErrors ||= newFeedState.hasFeedErrors; + personalCardStates.shouldShowRBR ||= shouldShowRBR; + } + + function addErrorsForCard(card: Card) { + const bankName = card.bank; + const workspaceAccountID = Number(card.fundID); + + const isExpensifyCard = bankName === CONST.EXPENSIFY_CARD.BANK; + + if (Number.isNaN(workspaceAccountID)) { + return; + } + + const feedNameWithDomainID = getCardFeedWithDomainID(bankName, workspaceAccountID); + const previousFeedErrors = cardFeedErrors[feedNameWithDomainID] ?? DEFAULT_CARD_FEED_ERROR_STATE; + + const feed = combinedCompanyCardFeeds?.[feedNameWithDomainID]; + const feedErrors = { + ...previousFeedErrors.feedErrors, + ...feed?.errors, + } as Errors; + const hasFeedErrors = feedNameWithDomainID ? !isEmptyObject(feedErrors) : false; + + const workspaceErrors = workspaceCardFeedsStatus?.[workspaceAccountID]?.errors; + const hasWorkspaceErrors = !!workspaceErrors; + + const hasCardErrors = !isEmptyObject(card.errors) || !isEmptyObject(card.errorFields) || card.pendingAction; + const cardErrors = { + ...previousFeedErrors.cardErrors, + ...(cardFeedErrors[feedNameWithDomainID]?.cardErrors ?? {}), + ...(hasCardErrors + ? { + [card.cardID]: { + errors: card.errors, + errorFields: card.errorFields, + pendingAction: card.pendingAction, + }, + } + : {}), + } as Record; + + // Keep the broken state itself truthful: the Company cards page renders its "log into your bank" fix from + // this flag, and the reconnect needs it to clear the error afterwards. Only stop *prompting* (the RBR and + // the time-sensitive task) once the connection has been unresolved past the grace period. + const isFeedConnectionBroken = isCardConnectionBroken(card); + const shouldPromptBrokenConnection = isFeedConnectionBroken && !isBrokenConnectionPastDismissThreshold(card); + + const newFeedState: Omit = { + isFeedConnectionBroken: isFeedConnectionBroken || previousFeedErrors.isFeedConnectionBroken, + shouldPromptBrokenConnection: shouldPromptBrokenConnection || previousFeedErrors.shouldPromptBrokenConnection, + hasFeedErrors: hasFeedErrors || previousFeedErrors.hasFeedErrors, + hasWorkspaceErrors: hasWorkspaceErrors || previousFeedErrors.hasWorkspaceErrors, + hasFeedConnectionIssue: hasCardConnectionIssue(card) || previousFeedErrors.hasFeedConnectionIssue, + }; + + const shouldShowRBR = getShouldShowRBR(newFeedState) || previousFeedErrors.shouldShowRBR; + + cardFeedErrors[feedNameWithDomainID] = { + ...newFeedState, + shouldShowRBR, + cardErrors, + feedErrors, + workspaceErrors, + }; + + // Track cards with broken feed connection. This stays truthful past the grace period so that reconnecting + // still clears the error (see useUpdateFeedBrokenConnection); consumers that prompt the user filter on the + // grace period themselves. + if (isFeedConnectionBroken) { + cardsWithBrokenFeedConnection[card.cardID] = card; + } + + // Update aggregate states - once true, always stays true + const cardTypeState = isExpensifyCard ? expensifyCardFeedStates : companyCardFeedsState; + + allFeedsState.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken; + allFeedsState.shouldPromptBrokenConnection ||= newFeedState.shouldPromptBrokenConnection; + allFeedsState.hasFeedErrors ||= newFeedState.hasFeedErrors; + allFeedsState.hasWorkspaceErrors ||= newFeedState.hasWorkspaceErrors; + allFeedsState.hasFeedConnectionIssue ||= newFeedState.hasFeedConnectionIssue; + + cardTypeState.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken; + cardTypeState.shouldPromptBrokenConnection ||= newFeedState.shouldPromptBrokenConnection; + cardTypeState.hasFeedErrors ||= newFeedState.hasFeedErrors; + cardTypeState.hasWorkspaceErrors ||= newFeedState.hasWorkspaceErrors; + cardTypeState.hasFeedConnectionIssue ||= newFeedState.hasFeedConnectionIssue; + + shouldShowRbrForWorkspaceAccountID[workspaceAccountID] ||= shouldShowRBR; + shouldShowRbrForFeedNameWithDomainID[feedNameWithDomainID] ||= shouldShowRBR; + } + + for (const card of Object.values(globalCardList ?? {})) { + const isPersonal = isPersonalCard(card); + if (isPersonal) { + addErrorsForPersonalCard(card); + } else { + addErrorsForCard(card); + } + } + + const workspaceCards = allWorkspaceCards ?? {}; + for (const key of Object.keys(workspaceCards)) { + const keyParts = key.split(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST); + const workspaceCardParamParts = keyParts.at(1)?.split('_'); + + if (!workspaceCardParamParts) { + continue; + } + + forEachAssignedCard(filterAllInactiveCards(workspaceCards[key]), addErrorsForCard); + } + + allFeedsState.shouldShowRBR = getShouldShowRBR(allFeedsState); + companyCardFeedsState.shouldShowRBR = getShouldShowRBR(companyCardFeedsState); + expensifyCardFeedStates.shouldShowRBR = getShouldShowRBR(expensifyCardFeedStates); + + return { + // The errors of all card feeds. + cardFeedErrors, + cardsWithBrokenFeedConnection, + personalCardsWithBrokenConnection, + + // Mappings of whether to show the RBR for each workspace account ID and per feed name with domain ID + shouldShowRbrForWorkspaceAccountID, + shouldShowRbrForFeedNameWithDomainID, + + // Whether any of the feeds have one of the below errors + all: allFeedsState, + + // Whether any of the company cards have one of the below errors + companyCards: companyCardFeedsState, + + // Whether any of the expensify cards have one of the below errors + expensifyCard: expensifyCardFeedStates, + + // Whether any of the personal cards have one of the below errors + personalCard: personalCardStates, + }; +} + +type CardFeedErrorsCacheEntry = { + globalCardList: OnyxEntry; + allWorkspaceCards: OnyxCollection; + cardFeeds: OnyxCollection; + currentDate: OnyxEntry; + cardFeedErrors: CardFeedErrors; +}; + +let lastEntry: CardFeedErrorsCacheEntry | undefined; + +/** + * Memoized on the input references, which Onyx keeps stable until they change, so every mounted consumer shares one + * compute per write. The current date is part of the key because the grace-period checks read the clock. + */ +function getCardFeedErrors( + globalCardList: OnyxEntry, + allWorkspaceCards: OnyxCollection, + cardFeeds: OnyxCollection, + currentDate: OnyxEntry, +): CardFeedErrors { + if ( + lastEntry && + lastEntry.globalCardList === globalCardList && + lastEntry.allWorkspaceCards === allWorkspaceCards && + lastEntry.cardFeeds === cardFeeds && + lastEntry.currentDate === currentDate + ) { + return lastEntry.cardFeedErrors; + } + const cardFeedErrors = computeCardFeedErrors(globalCardList, allWorkspaceCards, cardFeeds); + lastEntry = {globalCardList, allWorkspaceCards, cardFeeds, currentDate, cardFeedErrors}; + return cardFeedErrors; +} + +export {computeCardFeedErrors, getCardFeedErrors}; diff --git a/src/types/onyx/DerivedValues.ts b/src/types/onyx/DerivedValues.ts index 3f5e2a136157..13971642abfd 100644 --- a/src/types/onyx/DerivedValues.ts +++ b/src/types/onyx/DerivedValues.ts @@ -184,11 +184,6 @@ type CardFeedErrors = { personalCard: CardFeedErrorState; }; -/** - * The derived value for card feed errors. - */ -type CardFeedErrorsDerivedValue = CardFeedErrors; - /** * The derived value for merged non-personal and workspace card feeds. */ @@ -254,7 +249,6 @@ export type { SortedReportActionsDerivedValue, NonPersonalAndWorkspaceCardListDerivedValue, PersonalAndWorkspaceCardListDerivedValue, - CardFeedErrorsDerivedValue, LoginToAccountIDMapDerivedValue, GuideAccountIDsDerivedValue, SpendDataSignatureDerivedValue, diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index a86e9d85adb5..8ff8e8960987 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -59,7 +59,6 @@ import type {CurrencyList} from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type DatabaseSizeMeasurement from './DatabaseSizeMeasurement'; import type { - CardFeedErrorsDerivedValue, GuideAccountIDsDerivedValue, SpendDataSignatureDerivedValue, LoginToAccountIDMapDerivedValue, @@ -500,7 +499,6 @@ export type { SortedReportActionsDerivedValue, NonPersonalAndWorkspaceCardListDerivedValue, PersonalAndWorkspaceCardListDerivedValue, - CardFeedErrorsDerivedValue, LoginToAccountIDMapDerivedValue, GuideAccountIDsDerivedValue, SpendDataSignatureDerivedValue, diff --git a/tests/perf-test/CardFeedErrorsCardWrites.perf-test.tsx b/tests/perf-test/CardFeedErrorsCardWrites.perf-test.tsx new file mode 100644 index 000000000000..9fcfc0fd2016 --- /dev/null +++ b/tests/perf-test/CardFeedErrorsCardWrites.perf-test.tsx @@ -0,0 +1,347 @@ +import {render, screen} from '@testing-library/react-native'; + +import ComposeProviders from '@components/ComposeProviders'; +import OnyxListItemProvider from '@components/OnyxListItemProvider'; +import TransactionPreviewContent from '@components/ReportActionItem/TransactionPreview/TransactionPreviewContent'; +import WorkspaceRowBrickRoadIndicator from '@components/Tables/WorkspaceListTable/WorkspaceRowBrickRoadIndicator'; + +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Card, PersonalDetailsList, Policy, Report, ReportAction, Transaction, WorkspaceCardsList} from '@src/types/onyx'; + +import React from 'react'; +import {View} from 'react-native'; +import Onyx from 'react-native-onyx'; +import {measureAsyncFunction, measureRenders} from 'reassure'; + +import createMock from '../utils/createMock'; +import * as LHNTestUtils from '../utils/LHNTestUtils'; +import * as TestHelper from '../utils/TestHelper'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; + +jest.mock('@hooks/useScreenWrapperTransitionStatus', () => ({ + __esModule: true, + default: () => ({ + didScreenTransitionEnd: true, + }), +})); + +const WORKSPACE_COUNT = 20; +const PREVIEW_COUNT = 10; +const SMALL_CARDS_PER_WORKSPACE = 5; +const LARGE_CARDS_PER_WORKSPACE = 100; +const WRITES_PER_SCENARIO = 10; +const FIRST_WORKSPACE_ACCOUNT_ID = 70000; +const CURRENT_USER_ACCOUNT_ID = 1; +const CURRENT_USER_EMAIL = 'email1@test.com'; +const FEED = CONST.COMPANY_CARD.FEED_BANK_NAME.VISA; +const HEALTHY_SCRAPE_RESULT = 200; +const BROKEN_SCRAPE_RESULT = 403; + +const workspaceIndexes = Array.from({length: WORKSPACE_COUNT}, (value, index) => index); +const previewIndexes = Array.from({length: PREVIEW_COUNT}, (value, index) => index); + +function getPolicyID(workspaceIndex: number) { + return `cardFeedErrorsPolicy${workspaceIndex}`; +} + +function getWorkspaceAccountID(workspaceIndex: number) { + return FIRST_WORKSPACE_ACCOUNT_ID + workspaceIndex; +} + +function getWorkspaceCardsKey(workspaceIndex: number) { + return `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${getWorkspaceAccountID(workspaceIndex)}_${FEED}` as const; +} + +function getCardID(workspaceIndex: number, cardIndex: number) { + return getWorkspaceAccountID(workspaceIndex) * 1000 + cardIndex; +} + +function createCard(workspaceIndex: number, cardIndex: number): Card { + return { + cardID: getCardID(workspaceIndex, cardIndex), + accountID: CURRENT_USER_ACCOUNT_ID, + bank: FEED, + fundID: String(getWorkspaceAccountID(workspaceIndex)), + cardName: `Card ${cardIndex}`, + domainName: 'test.exfy', + fraud: CONST.EXPENSIFY_CARD.FRAUD_TYPES.NONE, + lastFourPAN: '1234', + lastScrape: '', + lastUpdated: '', + lastScrapeResult: HEALTHY_SCRAPE_RESULT, + state: CONST.EXPENSIFY_CARD.STATE.OPEN, + }; +} + +function createWorkspaceCards(cardsPerWorkspace: number) { + return Object.fromEntries( + workspaceIndexes.map((workspaceIndex) => { + const cards: WorkspaceCardsList = Object.fromEntries( + Array.from({length: cardsPerWorkspace}, (value, cardIndex) => [String(getCardID(workspaceIndex, cardIndex)), createCard(workspaceIndex, cardIndex)]), + ); + return [getWorkspaceCardsKey(workspaceIndex), cards]; + }), + ); +} + +const policies = Object.fromEntries( + workspaceIndexes.map((workspaceIndex) => [ + `${ONYXKEYS.COLLECTION.POLICY}${getPolicyID(workspaceIndex)}`, + createMock({ + id: getPolicyID(workspaceIndex), + name: `Workspace ${workspaceIndex}`, + type: CONST.POLICY.TYPE.CORPORATE, + role: CONST.POLICY.ROLE.ADMIN, + owner: CURRENT_USER_EMAIL, + outputCurrency: CONST.CURRENCY.USD, + policyAccountID: getWorkspaceAccountID(workspaceIndex), + }), + ]), +); + +const personalDetails: PersonalDetailsList = { + [CURRENT_USER_ACCOUNT_ID]: {accountID: CURRENT_USER_ACCOUNT_ID, login: CURRENT_USER_EMAIL, displayName: 'One'}, +}; + +function getReportID(previewIndex: number) { + return `cardFeedErrorsReport${previewIndex}`; +} + +function getTransactionID(previewIndex: number) { + return `cardFeedErrorsTransaction${previewIndex}`; +} + +const previewReports = previewIndexes.map((previewIndex) => + createMock({ + reportID: getReportID(previewIndex), + type: CONST.REPORT.TYPE.EXPENSE, + policyID: getPolicyID(0), + ownerAccountID: CURRENT_USER_ACCOUNT_ID, + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, + }), +); + +const previewTransactions = previewIndexes.map((previewIndex) => + createMock({ + transactionID: getTransactionID(previewIndex), + reportID: getReportID(previewIndex), + amount: 5000, + currency: CONST.CURRENCY.USD, + created: '2026-04-20', + merchant: `Merchant ${previewIndex}`, + comment: {}, + }), +); + +const previewActions = previewIndexes.map((previewIndex) => + createMock({ + ...LHNTestUtils.getFakeReportAction(), + reportActionID: `cardFeedErrorsAction${previewIndex}`, + reportID: getReportID(previewIndex), + actionName: CONST.REPORT.ACTIONS.TYPE.IOU, + actorAccountID: CURRENT_USER_ACCOUNT_ID, + originalMessage: { + type: CONST.IOU.REPORT_ACTION_TYPE.CREATE, + IOUTransactionID: getTransactionID(previewIndex), + amount: 5000, + currency: CONST.CURRENCY.USD, + }, + }), +); + +const noop = () => {}; + +/** Workspace list rows, each subscribed to whether its own workspace shows the card feed RBR */ +function WorkspaceRows() { + return ( + + {workspaceIndexes.map((workspaceIndex) => ( + + ))} + + ); +} + +/** Expense previews, the report-action items that read the whole card feed errors value */ +function TransactionPreviews() { + return ( + <> + {previewIndexes.map((previewIndex) => ( + ({})} + isWhisper={false} + isHovered={false} + chatReport={undefined} + personalDetails={personalDetails} + report={previewReports.at(previewIndex)} + policy={undefined} + transaction={previewTransactions.at(previewIndex)} + violations={[]} + transactionRawAmount={5000} + offlineWithFeedbackOnClose={noop} + containerStyles={[]} + transactionPreviewWidth={303} + isBillSplit={false} + areThereDuplicates={false} + sessionAccountID={CURRENT_USER_ACCOUNT_ID} + walletTermsErrors={undefined} + reportPreviewAction={undefined} + navigateToReviewFields={noop} + routeName="Report" + /> + ))} + + ); +} + +/** Report-action previews and workspace rows mounted together, so every write reaches many card feed error consumers */ +function CardFeedErrorsConsumers() { + return ( + + + + + ); +} + +async function seed(cardsPerWorkspace: number) { + await Onyx.multiSet({ + [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, + ...policies, + ...createWorkspaceCards(cardsPerWorkspace), + ...Object.fromEntries(previewReports.map((report) => [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report])), + ...Object.fromEntries(previewTransactions.map((transaction) => [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, transaction])), + }); + await waitForBatchedUpdates(); +} + +/** Renames a healthy card, which changes no error */ +async function renameHealthyCard(label: string) { + for (let index = 0; index < WRITES_PER_SCENARIO; index++) { + await Onyx.merge(getWorkspaceCardsKey(0), {[getCardID(0, 0)]: {cardName: `Renamed ${label}-${index}`}}); + await waitForBatchedUpdates(); + } +} + +/** Breaks and repairs one card's bank connection, so every write changes the errors; ends healthy so runs can repeat */ +async function toggleBrokenCard() { + for (let index = 0; index < WRITES_PER_SCENARIO; index++) { + const lastScrapeResult = index % 2 === 0 ? BROKEN_SCRAPE_RESULT : HEALTHY_SCRAPE_RESULT; + await Onyx.merge(getWorkspaceCardsKey(0), {[getCardID(0, 0)]: {lastScrapeResult}}); + await waitForBatchedUpdates(); + } +} + +describe('Card feed errors consumers on card writes', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + require('@userActions/OnyxDerived').default(); + }); + + beforeEach(async () => { + global.fetch = TestHelper.getGlobalFetchMock(); + wrapOnyxWithWaitForBatchedUpdates(Onyx); + await TestHelper.signInWithTestUser(CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, undefined, 'One'); + await waitForBatchedUpdates(); + }); + + afterEach(async () => { + await Onyx.clear(); + await waitForBatchedUpdates(); + }); + + test('[CardFeedErrors] should re-render when a healthy card is renamed', async () => { + // Given ten expense previews and twenty workspace rows over a small set of healthy workspace cards + await seed(SMALL_CARDS_PER_WORKSPACE); + + // Reassure runs the scenario several times against one seeded Onyx, so every run writes a name that doesn't exist yet + let run = 0; + const scenario = async () => { + await screen.findByTestId('workspace-rows'); + + // When a healthy card is renamed repeatedly, which leaves the card feed errors unchanged + await renameHealthyCard(`small-${run}`); + run++; + }; + + // Then reassure measures what the unrelated writes cost the consumers + await measureRenders(, {scenario}); + }); + + test('[CardFeedErrors] should not re-render workspace rows when a healthy card is renamed', async () => { + // Given only the workspace rows, which don't read the report attributes, so their renders isolate card feed error churn + await seed(SMALL_CARDS_PER_WORKSPACE); + + let run = 0; + const scenario = async () => { + await screen.findByTestId('workspace-rows'); + + // When a healthy card is renamed repeatedly + await renameHealthyCard(`rows-${run}`); + run++; + }; + + // Then every extra render comes from the card feed errors changing without a new RBR state + await measureRenders(, {scenario}); + }); + + test('[CardFeedErrors] should re-render when a healthy card is renamed in a large card list', async () => { + // Given the same consumers over 2000 workspace cards + await seed(LARGE_CARDS_PER_WORKSPACE); + + let run = 0; + const scenario = async () => { + await screen.findByTestId('workspace-rows'); + + // When a healthy card is renamed repeatedly, so every write rebuilds the errors from every card + await renameHealthyCard(`large-${run}`); + run++; + }; + + // Then reassure measures the render cost, which grows if each consumer rebuilds the errors on its own + await measureRenders(, {scenario}); + }); + + test('[CardFeedErrors] should re-render when a card connection breaks and is repaired', async () => { + // Given the consumers over a small set of healthy workspace cards + await seed(SMALL_CARDS_PER_WORKSPACE); + + const scenario = async () => { + await screen.findByTestId('workspace-rows'); + + // When one card's bank connection breaks and is repaired, so the errors and the first workspace's RBR really change + await toggleBrokenCard(); + }; + + // Then reassure measures the cost of a real error change, which both versions have to pay + await measureRenders(, {scenario}); + }); + + test('[CardFeedErrors] should process healthy card renames in a large card list', async () => { + // Given the consumers mounted over 2000 workspace cards + await seed(LARGE_CARDS_PER_WORKSPACE); + render(); + await screen.findByTestId('workspace-rows'); + + // When a healthy card is renamed repeatedly + let run = 0; + const writeRenames = async () => { + await renameHealthyCard(`timed-${run}`); + run++; + }; + + // Then reassure times the whole write loop, including work done outside React renders such as derived computes and their writes + await measureAsyncFunction(writeRenames); + }); +}); diff --git a/tests/ui/TableTest.tsx b/tests/ui/TableTest.tsx index 29825bdc490c..4570ad085b50 100644 --- a/tests/ui/TableTest.tsx +++ b/tests/ui/TableTest.tsx @@ -2621,6 +2621,44 @@ describe('Table', () => { expect(screen.queryByTestId('row-2')).toBeNull(); expect(screen.getByTestId('generic-empty-state')).toBeTruthy(); }); + + it('renders the empty state instead of "No results" when a page-header table hides every row by default', () => { + // Given a page-header table (like the Workspaces list) whose default filter hides every row, with both + // a no-results state and an empty state declared + const props = createDefaultProps(); + const data: TestItem[] = [ + {keyForList: '1', id: '1', name: 'Archived A', category: 'archived', value: 1}, + {keyForList: '2', id: '2', name: 'Archived B', category: 'archived', value: 2}, + ]; + + // When the table renders with no search or filter selected + render( + + data={data} + columns={props.columns} + renderItem={props.renderItem} + keyExtractor={props.keyExtractor} + filters={statusFilterConfig} + isItemInFilter={isItemInStatusFilter} + > + + Page header + + + + + + , + ); + + // Then the empty state shows inside the list with the page header still visible, because the user did + // not search or filter, so "No results found" would be misleading + expect(screen.getByTestId('flash-list')).toBeTruthy(); + expect(screen.getByTestId('table-header-component')).toBeTruthy(); + expect(screen.getAllByTestId('generic-empty-state')).toHaveLength(1); + expect(screen.getByText('No workspaces')).toBeTruthy(); + expect(screen.queryByText('common.noResultsFound')).toBeNull(); + }); }); describe('immediate filter', () => { diff --git a/tests/unit/CardFeedErrorsDerivedValueTest.ts b/tests/unit/CardFeedErrorsSelectorTest.ts similarity index 87% rename from tests/unit/CardFeedErrorsDerivedValueTest.ts rename to tests/unit/CardFeedErrorsSelectorTest.ts index ee3c32662a4a..e60fe12c6733 100644 --- a/tests/unit/CardFeedErrorsDerivedValueTest.ts +++ b/tests/unit/CardFeedErrorsSelectorTest.ts @@ -1,18 +1,13 @@ -import type {DerivedValueContext} from '@libs/actions/OnyxDerived/types'; import {getCardFeedWithDomainID} from '@libs/CardUtils'; import CONST from '@src/CONST'; -import cardFeedErrorsConfig from '@src/libs/actions/OnyxDerived/configs/cardFeedErrors'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Card, CardFeeds, CardList, WorkspaceCardsList} from '@src/types/onyx'; import type {CardFeedWithDomainID, CardFeedWithNumber} from '@src/types/onyx/CardFeeds'; import type {OnyxCollection} from 'react-native-onyx'; -const DERIVED_VALUE_CONTEXT: DerivedValueContext = { - currentValue: undefined, - sourceValues: undefined, -}; +import {computeCardFeedErrors, getCardFeedErrors} from '@selectors/CardFeedErrors'; const CARD_FEEDS = { [CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE]: { @@ -70,10 +65,10 @@ function createWorkspaceCardsList(cards: Record): WorkspaceCardsLi return cards; } -describe('CardFeedErrors Derived Value', () => { +describe('computeCardFeedErrors', () => { describe('compute function', () => { it('should return empty errors when no cards exist', () => { - const result = cardFeedErrorsConfig.compute([{}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, {}, {}); expect(result.cardFeedErrors).toEqual({}); expect(result.cardsWithBrokenFeedConnection).toEqual({}); @@ -86,7 +81,7 @@ describe('CardFeedErrors Derived Value', () => { }); it('should return empty errors when all inputs are undefined', () => { - const result = cardFeedErrorsConfig.compute([undefined, undefined, undefined, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(undefined, undefined, undefined); expect(result.cardFeedErrors).toEqual({}); expect(result.all.shouldShowRBR).toBe(false); @@ -104,7 +99,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.isFeedConnectionBroken).toBe(true); expect(result.all.shouldShowRBR).toBe(true); @@ -122,7 +117,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.isFeedConnectionBroken).toBe(false); expect(result.cardsWithBrokenFeedConnection).toEqual({}); @@ -139,7 +134,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.isFeedConnectionBroken).toBe(false); }); @@ -155,7 +150,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.isFeedConnectionBroken).toBe(false); }); @@ -175,7 +170,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.shouldShowRBR).toBe(false); expect(result.all.shouldPromptBrokenConnection).toBe(false); @@ -201,7 +196,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.shouldShowRBR).toBe(true); expect(result.all.shouldPromptBrokenConnection).toBe(true); @@ -218,7 +213,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.isFeedConnectionBroken).toBe(true); expect(result.personalCardsWithBrokenConnection[CARD_IDS.card1]).toEqual(card); @@ -233,7 +228,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.isFeedConnectionBroken).toBe(false); expect(result.personalCardsWithBrokenConnection).toEqual({}); @@ -253,7 +248,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(true); // The connection itself is still dismissed, so the time-sensitive task stays away. @@ -270,7 +265,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(false); expect(result.personalCard.isFeedConnectionBroken).toBe(false); @@ -288,7 +283,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(true); expect(result.personalCard.isFeedConnectionBroken).toBe(true); @@ -309,7 +304,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(true); }); @@ -328,7 +323,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(false); }); @@ -345,7 +340,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(true); }); @@ -364,7 +359,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(false); expect(result.personalCard.isFeedConnectionBroken).toBe(false); @@ -381,7 +376,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.personalCard.shouldShowRBR).toBe(true); expect(result.personalCard.isFeedConnectionBroken).toBe(true); @@ -403,7 +398,7 @@ describe('CardFeedErrors Derived Value', () => { [`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${cardFeed.policyAccountID}_${cardFeed.feedNameWithDomainID}`]: createWorkspaceCardsList({card2: card}), }; - const result = cardFeedErrorsConfig.compute([{}, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, allWorkspaceCards, {}); expect(result.all.isFeedConnectionBroken).toBe(true); expect(result.cardsWithBrokenFeedConnection[CARD_IDS.card2]).toEqual(card); @@ -453,7 +448,7 @@ describe('CardFeedErrors Derived Value', () => { }), }; - const result = cardFeedErrorsConfig.compute([{}, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, allWorkspaceCards, {}); // Only the active card should be processed and detected as broken expect(result.cardsWithBrokenFeedConnection).toHaveProperty(String(CARD_IDS.card4)); @@ -490,7 +485,7 @@ describe('CardFeedErrors Derived Value', () => { }, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, cardFeeds, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, cardFeeds); expect(result.all.hasFeedErrors).toBe(true); expect(result.all.shouldShowRBR).toBe(true); @@ -526,7 +521,7 @@ describe('CardFeedErrors Derived Value', () => { // }, // }; - // const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, cardFeeds, undefined], DERIVED_VALUE_CONTEXT); + // const result = computeCardFeedErrors(globalCardList, {}, {}, cardFeeds); // expect(result.all.hasWorkspaceErrors).toBe(true); // expect(result.cardFeedErrors[cardFeed.feedNameWithDomainID]?.hasWorkspaceErrors).toBe(true); @@ -548,7 +543,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.cardFeedErrors[cardFeed.feedNameWithDomainID]?.cardErrors[CARD_IDS.card1]).toEqual({ errors: {cardError: 'Card sync failed'}, @@ -571,7 +566,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.cardFeedErrors[cardFeed.feedNameWithDomainID]?.cardErrors[CARD_IDS.card1]?.errorFields).toEqual({ cardName: {error: 'Invalid card name'}, @@ -590,7 +585,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.cardFeedErrors[cardFeed.feedNameWithDomainID]?.cardErrors[CARD_IDS.card1]?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); }); @@ -609,7 +604,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[cardFeed.policyAccountID]).toBe(true); }); @@ -626,7 +621,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForFeedNameWithDomainID[cardFeed.feedNameWithDomainID]).toBe(true); }); @@ -643,7 +638,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[cardFeed.policyAccountID]).toBe(false); expect(result.shouldShowRbrForFeedNameWithDomainID[cardFeed.feedNameWithDomainID]).toBe(false); @@ -671,7 +666,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card1, [CARD_IDS.card2]: card2}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[cardFeed1.policyAccountID]).toBe(true); expect(result.shouldShowRbrForWorkspaceAccountID[cardFeed2.policyAccountID]).toBe(false); @@ -704,7 +699,7 @@ describe('CardFeedErrors Derived Value', () => { }), }; - const result = cardFeedErrorsConfig.compute([globalCardList, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, allWorkspaceCards, {}); expect(result.cardsWithBrokenFeedConnection).toHaveProperty(String(CARD_IDS.card1)); expect(result.cardsWithBrokenFeedConnection).toHaveProperty(String(CARD_IDS.card2)); @@ -739,7 +734,7 @@ describe('CardFeedErrors Derived Value', () => { }, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, cardFeeds, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, cardFeeds); expect(result.all.shouldShowRBR).toBe(true); }); @@ -756,7 +751,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.shouldShowRBR).toBe(true); }); @@ -773,7 +768,7 @@ describe('CardFeedErrors Derived Value', () => { const globalCardList: CardList = {[CARD_IDS.card1]: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.all.shouldShowRBR).toBe(false); }); @@ -811,7 +806,7 @@ describe('CardFeedErrors Derived Value', () => { [CARD_IDS.card2]: healthyCard, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(true); expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(false); @@ -836,7 +831,7 @@ describe('CardFeedErrors Derived Value', () => { [CARD_IDS.card2]: fixedAmexCard, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(true); expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(false); @@ -862,7 +857,7 @@ describe('CardFeedErrors Derived Value', () => { [CARD_IDS.card2]: healthyAmexCard, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(false); expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(false); @@ -888,7 +883,7 @@ describe('CardFeedErrors Derived Value', () => { [CARD_IDS.card2]: brokenAmexCard, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(true); expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(true); @@ -933,7 +928,7 @@ describe('CardFeedErrors Derived Value', () => { }, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, cardFeeds, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, cardFeeds); expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(true); expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(false); @@ -941,3 +936,55 @@ describe('CardFeedErrors Derived Value', () => { }); }); }); + +describe('getCardFeedErrors', () => { + const cardFeed = CARD_FEEDS[CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE]; + + function createBrokenCardList(): CardList { + return {card1: createCard({cardID: CARD_IDS.card1, bank: cardFeed.feedName, fundID: String(cardFeed.policyAccountID), lastScrapeResult: 403})}; + } + + it('should return the same object while every input keeps its reference', () => { + // Given one set of inputs, as every consumer reads them from the same Onyx store between two writes + const globalCardList = createBrokenCardList(); + const allWorkspaceCards: OnyxCollection = {}; + const cardFeeds: OnyxCollection = {}; + + // When two consumers ask for the errors + const first = getCardFeedErrors(globalCardList, allWorkspaceCards, cardFeeds, '2026-10-08'); + const second = getCardFeedErrors(globalCardList, allWorkspaceCards, cardFeeds, '2026-10-08'); + + // Then they share one compute, so many mounted report actions don't each rebuild the errors + expect(second).toBe(first); + expect(first.all.isFeedConnectionBroken).toBe(true); + }); + + it('should recompute when an input changes reference', () => { + // Given errors computed from a card list with a broken card + const allWorkspaceCards: OnyxCollection = {}; + const cardFeeds: OnyxCollection = {}; + const first = getCardFeedErrors(createBrokenCardList(), allWorkspaceCards, cardFeeds, '2026-10-08'); + + // When the card list is replaced by one where the card syncs again + const fixedCardList: CardList = {card1: createCard({cardID: CARD_IDS.card1, bank: cardFeed.feedName, fundID: String(cardFeed.policyAccountID), lastScrapeResult: 200})}; + const second = getCardFeedErrors(fixedCardList, allWorkspaceCards, cardFeeds, '2026-10-08'); + + // Then the errors follow the new card list instead of the cached result + expect(second).not.toBe(first); + expect(second.all.isFeedConnectionBroken).toBe(false); + }); + + it('should recompute when the day changes even if the card data does not', () => { + // Given errors computed for one day + const globalCardList = createBrokenCardList(); + const allWorkspaceCards: OnyxCollection = {}; + const cardFeeds: OnyxCollection = {}; + const first = getCardFeedErrors(globalCardList, allWorkspaceCards, cardFeeds, '2026-10-08'); + + // When the current date rolls over with the same card data + const second = getCardFeedErrors(globalCardList, allWorkspaceCards, cardFeeds, '2026-10-09'); + + // Then the errors are rebuilt, because the grace-period checks read the clock + expect(second).not.toBe(first); + }); +}); diff --git a/tests/unit/CompanyCardsRBRTest.ts b/tests/unit/CompanyCardsRBRTest.ts index 1f29a4508f3e..d5a188ebd4a1 100644 --- a/tests/unit/CompanyCardsRBRTest.ts +++ b/tests/unit/CompanyCardsRBRTest.ts @@ -1,17 +1,12 @@ -import type {DerivedValueContext} from '@libs/actions/OnyxDerived/types'; import {getCardFeedWithDomainID} from '@libs/CardUtils'; import CONST from '@src/CONST'; -import cardFeedErrorsConfig from '@src/libs/actions/OnyxDerived/configs/cardFeedErrors'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Card, CardFeeds, CardList, WorkspaceCardsList} from '@src/types/onyx'; import type {OnyxCollection} from 'react-native-onyx'; -const DERIVED_VALUE_CONTEXT: DerivedValueContext = { - currentValue: undefined, - sourceValues: undefined, -}; +import {computeCardFeedErrors} from '@selectors/CardFeedErrors'; const WORKSPACE_ACCOUNT_ID = 99999999; @@ -62,7 +57,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }); const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); expect(result.all.isFeedConnectionBroken).toBe(true); @@ -84,7 +79,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }), }; - const result = cardFeedErrorsConfig.compute([{}, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, allWorkspaceCards, {}); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); expect(result.all.isFeedConnectionBroken).toBe(true); @@ -100,7 +95,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }); const globalCardList: CardList = {card1: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(false); expect(result.all.isFeedConnectionBroken).toBe(false); @@ -118,7 +113,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }); const globalCardList: CardList = {card3: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); expect(result.all.isFeedConnectionBroken).toBe(true); @@ -138,7 +133,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { [`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${PLAID_FEED.policyAccountID}_${PLAID_FEED.feedNameWithDomainID}`]: createWorkspaceCardsList({card4: card}), }; - const result = cardFeedErrorsConfig.compute([{}, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, allWorkspaceCards, {}); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); expect(result.all.isFeedConnectionBroken).toBe(true); @@ -154,7 +149,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }); const globalCardList: CardList = {card3: card}; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, {}); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(false); expect(result.all.isFeedConnectionBroken).toBe(false); @@ -188,7 +183,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, cardFeeds, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, cardFeeds); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); expect(result.all.hasFeedErrors).toBe(true); @@ -220,7 +215,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }, }; - const result = cardFeedErrorsConfig.compute([globalCardList, {}, cardFeeds, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors(globalCardList, {}, cardFeeds); expect(result.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); expect(result.all.hasFeedErrors).toBe(true); @@ -238,7 +233,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { lastScrapeResult: 403, }); - const brokenResult = cardFeedErrorsConfig.compute([{card1: brokenCard}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const brokenResult = computeCardFeedErrors({card1: brokenCard}, {}, {}); expect(brokenResult.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); // Then: connection is fixed (lastScrapeResult returns to 200) @@ -249,7 +244,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { lastScrapeResult: 200, }); - const fixedResult = cardFeedErrorsConfig.compute([{card1: fixedCard}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const fixedResult = computeCardFeedErrors({card1: fixedCard}, {}, {}); expect(fixedResult.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(false); expect(fixedResult.all.shouldShowRBR).toBe(false); expect(fixedResult.cardsWithBrokenFeedConnection).toEqual({}); @@ -264,7 +259,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { lastScrapeResult: 401, }); - const brokenResult = cardFeedErrorsConfig.compute([{card3: brokenCard}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const brokenResult = computeCardFeedErrors({card3: brokenCard}, {}, {}); expect(brokenResult.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); // Then: Plaid re-authenticated successfully @@ -275,7 +270,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { lastScrapeResult: 200, }); - const fixedResult = cardFeedErrorsConfig.compute([{card3: fixedCard}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const fixedResult = computeCardFeedErrors({card3: fixedCard}, {}, {}); expect(fixedResult.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(false); expect(fixedResult.all.shouldShowRBR).toBe(false); expect(fixedResult.cardsWithBrokenFeedConnection).toEqual({}); @@ -298,7 +293,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }), }; - const result = cardFeedErrorsConfig.compute([{}, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, allWorkspaceCards, {}); expect(result.cardsWithBrokenFeedConnection).not.toHaveProperty('1'); }); @@ -318,7 +313,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { }), }; - const result = cardFeedErrorsConfig.compute([{}, allWorkspaceCards, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({}, allWorkspaceCards, {}); expect(result.cardsWithBrokenFeedConnection).not.toHaveProperty('3'); }); @@ -333,7 +328,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { lastScrapeResult: status, }); - const result = cardFeedErrorsConfig.compute([{card1: card}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({card1: card}, {}, {}); expect(result.all.isFeedConnectionBroken).toBe(false); expect(result.cardsWithBrokenFeedConnection).toEqual({}); @@ -347,7 +342,7 @@ describe('Company Cards RBR - broken bank/Plaid connection', () => { lastScrapeResult: status, }); - const result = cardFeedErrorsConfig.compute([{card3: card}, {}, {}, undefined], DERIVED_VALUE_CONTEXT); + const result = computeCardFeedErrors({card3: card}, {}, {}); expect(result.all.isFeedConnectionBroken).toBe(false); expect(result.cardsWithBrokenFeedConnection).toEqual({}); diff --git a/tests/unit/HomePage/YourSpendSection/useYourSpendDataTest.ts b/tests/unit/HomePage/YourSpendSection/useYourSpendDataTest.ts index a5e3d40be5d2..9b5c0b8a0039 100644 --- a/tests/unit/HomePage/YourSpendSection/useYourSpendDataTest.ts +++ b/tests/unit/HomePage/YourSpendSection/useYourSpendDataTest.ts @@ -145,6 +145,13 @@ jest.mock('@hooks/useOnyx', () => ({ default: (key: string, options?: {selector?: (v: unknown) => unknown}) => mockUseOnyx(key, options), })); +let mockCardFeedErrors: CardFeedErrors; + +jest.mock('@hooks/useCardFeedErrors', () => ({ + __esModule: true, + default: () => mockCardFeedErrors, +})); + // Helpers function makeCorporatePolicy(overrides: Partial = {}): Policy { @@ -222,7 +229,7 @@ function setupCardGroups(groups: CardGroupFixture[], searchOverrides: Partial = {}): CardFeedErrors { const defaultState: CardFeedErrorState = { shouldShowRBR: false, @@ -282,6 +289,7 @@ beforeEach(() => { for (const k of Object.keys(onyxData)) { delete onyxData[k]; } + mockCardFeedErrors = makeCardFeedErrors(); mockUseOnyx.mockClear(); mockedSearch.mockClear(); mockedUseIsTabFocused.mockReturnValue(true); @@ -774,20 +782,20 @@ describe('useYourSpendData — third-party cardRows', () => { // Start: card is in broken-feed-connection map → row absent. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const brokenCard = makeThirdPartyCards([{cardID: THIRD_PARTY_CARD_ID_1, lastFourPAN: THIRD_PARTY_LAST_FOUR_1}]).at(0)!; - onyxData[ONYXKEYS.DERIVED.CARD_FEED_ERRORS] = makeCardFeedErrors({cardsWithBrokenFeedConnection: {[THIRD_PARTY_CARD_ID_1]: brokenCard}}); + mockCardFeedErrors = makeCardFeedErrors({cardsWithBrokenFeedConnection: {[THIRD_PARTY_CARD_ID_1]: brokenCard}}); const {result, rerender} = renderHook(() => useYourSpendData()); expect(result.current.cardRows).toHaveLength(0); - // Mutate Onyx: remove the broken-feed entry → row should appear on re-render. + // Remove the broken-feed entry → row should appear on re-render. act(() => { - onyxData[ONYXKEYS.DERIVED.CARD_FEED_ERRORS] = makeCardFeedErrors({cardsWithBrokenFeedConnection: {}}); + mockCardFeedErrors = makeCardFeedErrors({cardsWithBrokenFeedConnection: {}}); }); rerender(undefined); expect(result.current.cardRows).toHaveLength(1); // And back: re-add the broken-feed entry → row should disappear. act(() => { - onyxData[ONYXKEYS.DERIVED.CARD_FEED_ERRORS] = makeCardFeedErrors({cardsWithBrokenFeedConnection: {[THIRD_PARTY_CARD_ID_1]: brokenCard}}); + mockCardFeedErrors = makeCardFeedErrors({cardsWithBrokenFeedConnection: {[THIRD_PARTY_CARD_ID_1]: brokenCard}}); }); rerender(undefined); expect(result.current.cardRows).toHaveLength(0); diff --git a/tests/unit/hooks/useAssignCard.test.ts b/tests/unit/hooks/useAssignCard.test.ts index 7e32d1926411..eb8c5eb8c94a 100644 --- a/tests/unit/hooks/useAssignCard.test.ts +++ b/tests/unit/hooks/useAssignCard.test.ts @@ -2,6 +2,7 @@ import {renderHook} from '@testing-library/react-native'; import useAssignCard from '@hooks/useAssignCard'; +import useCardFeedErrors from '@hooks/useCardFeedErrors'; import useCardFeeds from '@hooks/useCardFeeds'; import useIsAllowedToIssueCompanyCard from '@hooks/useIsAllowedToIssueCompanyCard'; import useNetwork from '@hooks/useNetwork'; @@ -68,6 +69,11 @@ jest.mock('@hooks/useOnyx', () => ({ })); // Mock all the hooks +jest.mock('@hooks/useCardFeedErrors', () => ({ + __esModule: true, + default: jest.fn(), +})); + jest.mock('@hooks/useCardFeeds', () => ({ __esModule: true, default: jest.fn(), @@ -137,6 +143,7 @@ describe('useAssignCard', () => { jest.mocked(useNetwork).mockReturnValue({isOffline: false}); jest.mocked(useIsAllowedToIssueCompanyCard).mockReturnValue(true); jest.mocked(useOnyx).mockReturnValue([undefined, {status: 'loaded'}]); + jest.mocked(useCardFeedErrors).mockReturnValue(createMock({cardFeedErrors: {}})); }); afterEach(async () => { @@ -194,17 +201,12 @@ describe('useAssignCard', () => { expect(result.current.isAssigningCardDisabled).toBe(false); }); - /** Points the mocked useOnyx at a CARD_FEED_ERRORS value for the custom (commercial) feed. */ + /** Points the mocked useCardFeedErrors at an error state for the custom (commercial) feed. */ function mockFeedErrors(feedErrorState: Partial) { - jest.mocked(useOnyx).mockImplementation((key) => - key === ONYXKEYS.DERIVED.CARD_FEED_ERRORS - ? [ - createMock({ - cardFeedErrors: {[mockCustomFeed]: {shouldShowRBR: false, hasFeedErrors: false, hasWorkspaceErrors: false, isFeedConnectionBroken: false, ...feedErrorState}}, - }), - {status: 'loaded'}, - ] - : [undefined, {status: 'loaded'}], + jest.mocked(useCardFeedErrors).mockReturnValue( + createMock({ + cardFeedErrors: {[mockCustomFeed]: {shouldShowRBR: false, hasFeedErrors: false, hasWorkspaceErrors: false, isFeedConnectionBroken: false, ...feedErrorState}}, + }), ); } diff --git a/tests/unit/useCardFeedErrorsTest.ts b/tests/unit/useCardFeedErrorsTest.ts new file mode 100644 index 000000000000..003bc1883450 --- /dev/null +++ b/tests/unit/useCardFeedErrorsTest.ts @@ -0,0 +1,105 @@ +import {act, renderHook} from '@testing-library/react-native'; + +import useCardFeedErrors from '@hooks/useCardFeedErrors'; + +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Card} from '@src/types/onyx'; + +import Onyx from 'react-native-onyx'; + +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; + +const WORKSPACE_ACCOUNT_ID = 44444444; +const BROKEN_CARD_ID = 1; +const HEALTHY_PERSONAL_CARD_ID = 2; + +function createBrokenCard(overrides: Partial = {}): Card { + return { + cardID: BROKEN_CARD_ID, + accountID: 1, + bank: CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE, + fundID: String(WORKSPACE_ACCOUNT_ID), + cardName: 'Broken card', + domainName: 'test.exfy', + fraud: 'none', + lastFourPAN: '1234', + lastScrape: '', + lastUpdated: '', + lastScrapeResult: 403, + state: CONST.EXPENSIFY_CARD.STATE.OPEN, + ...overrides, + }; +} + +describe('useCardFeedErrors', () => { + beforeAll(() => { + Onyx.init({keys: ONYXKEYS}); + }); + + beforeEach(async () => { + await Onyx.clear(); + await waitForBatchedUpdates(); + }); + + it('should return the errors computed from the card inputs', async () => { + // Given a company card whose bank connection is broken + await Onyx.set(ONYXKEYS.CARD_LIST, {[BROKEN_CARD_ID]: createBrokenCard()}); + await waitForBatchedUpdates(); + + // When the errors are read + const {result} = renderHook(() => useCardFeedErrors()); + + // Then the broken card lights the RBR of its workspace, as the derived value did + expect(result.current.all.isFeedConnectionBroken).toBe(true); + expect(result.current.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(true); + }); + + it('should keep the same reference when a card write leaves the errors unchanged', async () => { + // Given the errors of a broken card + await Onyx.set(ONYXKEYS.CARD_LIST, {[BROKEN_CARD_ID]: createBrokenCard()}); + await waitForBatchedUpdates(); + const {result} = renderHook(() => useCardFeedErrors()); + const before = result.current; + + // When a healthy personal card is added, which doesn't change any error + await act(async () => { + await Onyx.merge(ONYXKEYS.CARD_LIST, {[HEALTHY_PERSONAL_CARD_ID]: createBrokenCard({cardID: HEALTHY_PERSONAL_CARD_ID, fundID: '0', lastScrapeResult: 200})}); + await waitForBatchedUpdates(); + }); + + // Then consumers get the previous object, so they don't re-render + expect(result.current).toBe(before); + }); + + it('should apply a selector so a row only follows its own workspace', async () => { + // Given a broken card on one workspace + await Onyx.set(ONYXKEYS.CARD_LIST, {[BROKEN_CARD_ID]: createBrokenCard()}); + await waitForBatchedUpdates(); + + // When a row of that workspace and a row of another workspace select their flag + const {result: brokenRow} = renderHook(() => useCardFeedErrors((errors) => !!errors.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID])); + const {result: otherRow} = renderHook(() => useCardFeedErrors((errors) => !!errors.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID + 1])); + + // Then only the row of the broken workspace shows the RBR + expect(brokenRow.current).toBe(true); + expect(otherRow.current).toBe(false); + }); + + it('should update when a card write fixes the connection', async () => { + // Given the errors of a broken card + await Onyx.set(ONYXKEYS.CARD_LIST, {[BROKEN_CARD_ID]: createBrokenCard()}); + await waitForBatchedUpdates(); + const {result} = renderHook(() => useCardFeedErrors()); + + // When the card syncs again + await act(async () => { + await Onyx.merge(ONYXKEYS.CARD_LIST, {[BROKEN_CARD_ID]: {lastScrapeResult: 200}}); + await waitForBatchedUpdates(); + }); + + // Then the RBR goes away + expect(result.current.all.isFeedConnectionBroken).toBe(false); + expect(result.current.shouldShowRbrForWorkspaceAccountID[WORKSPACE_ACCOUNT_ID]).toBe(false); + }); +});