@mswjs/interceptors 0.42.3 → 0.42.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/lib/browser/interceptors/WebSocket/index.js +14 -1
  2. package/lib/browser/interceptors/WebSocket/index.js.map +1 -1
  3. package/lib/browser/interceptors/fetch/web.js +1 -1
  4. package/lib/browser/presets/browser.js +1 -1
  5. package/lib/browser/{web-CdcYFjgm.js → web-DUlFZEtz.js} +58 -3
  6. package/lib/browser/web-DUlFZEtz.js.map +1 -0
  7. package/lib/node/{batch-interceptor-ByEZVih3.js → batch-interceptor-DMOfd-9x.js} +2 -2
  8. package/lib/node/{batch-interceptor-ByEZVih3.js.map → batch-interceptor-DMOfd-9x.js.map} +1 -1
  9. package/lib/node/buffer-utils-B4FUq-l2.js +17 -0
  10. package/lib/node/buffer-utils-B4FUq-l2.js.map +1 -0
  11. package/lib/node/create-request-id-DHo-fRTV.js +14 -0
  12. package/lib/node/create-request-id-DHo-fRTV.js.map +1 -0
  13. package/lib/node/{fetch-utils-Dw1PsmtX.js → fetch-utils-D-_xeRlK.js} +3 -14
  14. package/lib/node/{fetch-utils-Dw1PsmtX.js.map → fetch-utils-D-_xeRlK.js.map} +1 -1
  15. package/lib/node/{has-configurable-global-BU1sT1u4.js → has-configurable-global-CT6-QYdg.js} +2 -2
  16. package/lib/node/{has-configurable-global-BU1sT1u4.js.map → has-configurable-global-CT6-QYdg.js.map} +1 -1
  17. package/lib/node/index.d.ts +2 -243
  18. package/lib/node/index.js +6 -25
  19. package/lib/node/index.js.map +1 -1
  20. package/lib/node/{buffer-utils-BvPY1Tc-.js → interceptor-C8qRPjxG.js} +2 -16
  21. package/lib/node/interceptor-C8qRPjxG.js.map +1 -0
  22. package/lib/node/interceptors/ClientRequest/index.js +3 -3
  23. package/lib/node/interceptors/WebSocket/index.d.ts +2 -0
  24. package/lib/node/interceptors/WebSocket/index.js +635 -0
  25. package/lib/node/interceptors/WebSocket/index.js.map +1 -0
  26. package/lib/node/interceptors/XMLHttpRequest/node.js +5 -5
  27. package/lib/node/interceptors/fetch/node.js +5 -5
  28. package/lib/node/interceptors/http/index.js +2 -2
  29. package/lib/node/interceptors/net/index.d.ts +16 -0
  30. package/lib/node/interceptors/net/index.js +1 -1
  31. package/lib/node/{net-Ca8p1rIe.js → net-Bh16MP4u.js} +82 -92
  32. package/lib/node/net-Bh16MP4u.js.map +1 -0
  33. package/lib/node/patches-registry-DxR5TEc-.js +76 -0
  34. package/lib/node/patches-registry-DxR5TEc-.js.map +1 -0
  35. package/lib/node/remote-http-interceptor.js +4 -4
  36. package/lib/node/resolve-web-socket-url-CSvNPLGi.js +25 -0
  37. package/lib/node/resolve-web-socket-url-CSvNPLGi.js.map +1 -0
  38. package/lib/node/{source-CIgPng7r.js → source-DHVO1vzq.js} +327 -213
  39. package/lib/node/source-DHVO1vzq.js.map +1 -0
  40. package/lib/node/websocket-CC0nB0md.d.ts +285 -0
  41. package/package.json +5 -2
  42. package/src/interceptors/WebSocket/index.ts +4 -1
  43. package/src/interceptors/fetch/web.ts +11 -2
  44. package/src/interceptors/http/http-parser/index.ts +9 -1
  45. package/src/interceptors/http/http-parser.ts +21 -4
  46. package/src/interceptors/http/source.ts +368 -283
  47. package/src/interceptors/net/index.ts +39 -12
  48. package/src/interceptors/net/socket-controller.ts +126 -66
  49. package/src/utils/clone-response.ts +72 -0
  50. package/src/utils/internal-connection.ts +22 -0
  51. package/lib/browser/web-CdcYFjgm.js.map +0 -1
  52. package/lib/node/buffer-utils-BvPY1Tc-.js.map +0 -1
  53. package/lib/node/net-Ca8p1rIe.js.map +0 -1
  54. package/lib/node/source-CIgPng7r.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"net-Ca8p1rIe.js","names":["#replacements","logger","#awaitedVerdicts","#connectionOptions","#passthroughSocket","#realWriteGeneric","#bufferedWrites","#handleWrite","#clientCloseEmitted","#readsCorked","#corkedReads","#reset","#retargetedConnectionOptions","#onRealSocketConnect","#onRealSocketConnectionAttemptFailed","#onRealSocketConnectionAttemptTimeout","#onRealSocketData","#onRealSocketError","#onRealSocketEnd","#onRealSocketClose","#realHandleSwapped","#resetScheduled","#connectEmulated","#push","#acknowledgeWrite","#removeBufferedWrite","#clientEndPushed","#emitClientClose","#createRetargetedConnection","#onMockSocketDrain","#forwardClientFinish","#tlsConnectionOptions","#stopReusingUnpatchedSockets"],"sources":["../../src/utils/patches-registry.ts","../../src/interceptors/net/utils/normalize-net-connect-args.ts","../../src/interceptors/net/utils/flush-writes.ts","../../src/interceptors/net/utils/get-tls-connect-options.ts","../../src/interceptors/net/utils/address-info.ts","../../src/interceptors/net/socket-controller.ts","../../src/interceptors/net/utils/normalize-tls-connect-args.ts","../../src/interceptors/net/index.ts"],"sourcesContent":["import { invariant } from 'outvariant'\n\nclass PatchesRegistry {\n #replacements = new Map<object, Map<PropertyKey, () => void>>()\n\n public applyPatch<Owner extends object, K extends keyof Owner>(\n owner: Owner,\n key: K,\n getNextValue: (realValue: Owner[K]) => Owner[K]\n ): () => void {\n const ownerReplacements = this.#replacements.get(owner)\n\n invariant(\n !ownerReplacements?.has(key),\n `Failed to replace a global value at \"${String(key)}\": already replaced.`\n )\n\n const match = getDeepPropertyDescriptor(owner, key)\n\n if (typeof match === 'undefined') {\n console.warn(\n `Failed to replace a global value at \"${String(key)}\": not a global value.`\n )\n return () => {}\n }\n\n if (match.descriptor.configurable) {\n Object.defineProperty(owner, key, {\n value: getNextValue(owner[key]),\n enumerable: true,\n configurable: true,\n })\n } else if (match.descriptor.writable) {\n owner[key] = getNextValue(owner[key])\n } else {\n throw new Error(\n `Failed to patch a non-configurable non-writable property \"${key.toString()}\"`\n )\n }\n\n const restorePatch = () => {\n const currentReplacements = this.#replacements.get(owner)\n\n if (!currentReplacements?.has(key)) {\n return\n }\n\n if (match.owner === owner) {\n /**\n * @note Restoring non-configurable properties works as long as \"writable: true\"\n * and none of the other descriptor properties except for \"value\" have changed.\n */\n Object.defineProperty(match.owner, key, match.descriptor)\n } else {\n /**\n * @todo Delete the proxy property set by the registry.\n * If the match's owner isn't the original owner, the property is likely nested in the prototype.\n * The registry does not meddle with those, they are left intact.\n */\n Reflect.deleteProperty(owner, key)\n }\n\n currentReplacements.delete(key)\n\n if (currentReplacements.size === 0) {\n this.#replacements.delete(owner)\n }\n }\n\n if (ownerReplacements) {\n ownerReplacements.set(key, restorePatch)\n } else {\n this.#replacements.set(owner, new Map([[key, restorePatch]]))\n }\n\n return restorePatch\n }\n\n public restoreAllPatches(): void {\n const errors: Array<Error> = []\n\n for (const [, ownerReplacements] of this.#replacements) {\n for (const [, restorePatch] of ownerReplacements) {\n try {\n restorePatch()\n } catch (error) {\n if (error instanceof Error) {\n errors.push(error)\n } else {\n throw error\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new AggregateError(errors, 'FOO!')\n }\n }\n}\n\nexport const patchesRegistry = new PatchesRegistry()\n\ninterface DeepDescriptorMatch {\n owner: object\n descriptor: PropertyDescriptor\n}\n\n/**\n * Returns a property descriptor for the given property on the owner.\n * Walks down the prototype chain if the property does not exist on the owner.\n * Handy for getting a global property descriptor where `globalThis` is\n * replaced with a controlled class (e.g. ServiceWorkerGlobalScope).\n */\nexport function getDeepPropertyDescriptor<Owner extends object>(\n owner: Owner,\n key: PropertyKey\n): DeepDescriptorMatch | undefined {\n let currentOwner: Owner | null = owner\n let descriptor: PropertyDescriptor | undefined\n\n while (currentOwner) {\n descriptor = Object.getOwnPropertyDescriptor(currentOwner, key)\n\n if (descriptor) {\n return {\n owner: currentOwner,\n descriptor,\n }\n }\n\n currentOwner = Object.getPrototypeOf(currentOwner)\n }\n}\n","import net from 'node:net'\n\nexport interface NetworkConnectionOptions {\n /**\n * @note The port may be a string when a URL is (incorrectly) passed\n * to `net.connect()`. Node.js reads URLs as plain options objects.\n */\n port?: number | string | null\n path: string | null\n host?: string | null\n protocol?: string | null\n auth?: string | null\n family?: number | null\n hints?: number | null\n session?: Buffer\n localAddress?: string | null\n localPort?: number | null\n timeout?: number\n lookup?: net.LookupFunction\n allowHalfOpen?: boolean | null\n noDelay?: boolean | null\n keepAlive?: boolean | null\n keepAliveInitialDelay?: number | null\n autoSelectFamily?: boolean | null\n autoSelectFamilyAttemptTimeout?: number | null\n}\n\nexport type NetConnectArgs =\n | []\n | [options: net.NetConnectOpts, callback?: () => void]\n | [url: URL, callback?: () => void]\n | [port: number, host?: string, callback?: () => void]\n | [port: number, callback?: () => void]\n | [path: string, callback?: () => void]\n\nexport type NormalizedNetConnectArgs = [\n options: NetworkConnectionOptions,\n callback: (() => void) | null,\n]\n\n/**\n * Normalizes the arguments passed to `net.connect()`.\n */\nexport function normalizeNetConnectArgs(\n args: NetConnectArgs\n): NormalizedNetConnectArgs {\n if (args.length === 0) {\n return [{ path: '' }, null]\n }\n\n const callback = typeof args[1] === 'function' ? args[1] : args[2] || null\n\n if (typeof args[0] === 'string') {\n return [{ path: args[0] }, callback]\n }\n\n if (typeof args[0] === 'number') {\n return [\n {\n port: args[0],\n path: '',\n /**\n * @note The host is optional in the \"(port[, host][, callback])\"\n * signatures and defaults to \"localhost\" in Node.js.\n */\n host: typeof args[1] === 'string' ? args[1] : undefined,\n },\n callback,\n ]\n }\n\n if (typeof args[0] === 'object') {\n /**\n * @note URL arguments receive no special treatment on purpose.\n * Node.js does not support them and reads a given URL as a plain\n * options object (e.g. \"url.port\" is a string, \"url.host\" includes\n * the port). The \"port\" branch below reproduces that reading.\n */\n if ('port' in args[0]) {\n return [\n {\n path: '',\n port: Reflect.get(args[0], 'port'),\n host: Reflect.get(args[0], 'host'),\n auth: Reflect.get(args[0], 'auth'),\n family: Reflect.get(args[0], 'family'),\n hints: Reflect.get(args[0], 'hints'),\n session: Reflect.get(args[0], 'session'),\n localAddress: Reflect.get(args[0], 'localAddress'),\n localPort: Reflect.get(args[0], 'localPort'),\n timeout: Reflect.get(args[0], 'timeout'),\n lookup: Reflect.get(args[0], 'lookup'),\n allowHalfOpen: Reflect.get(args[0], 'allowHalfOpen'),\n noDelay: Reflect.get(args[0], 'noDelay'),\n keepAlive: Reflect.get(args[0], 'keepAlive'),\n keepAliveInitialDelay: Reflect.get(args[0], 'keepAliveInitialDelay'),\n autoSelectFamily: Reflect.get(args[0], 'autoSelectFamily'),\n autoSelectFamilyAttemptTimeout: Reflect.get(\n args[0],\n 'autoSelectFamilyAttemptTimeout'\n ),\n },\n callback,\n ]\n }\n\n return [\n {\n path: args[0].path || '',\n family: Reflect.get(args[0], 'family'),\n session: Reflect.get(args[0], 'session'),\n auth: Reflect.get(args[0], 'auth'),\n timeout: Reflect.get(args[0], 'timeout'),\n allowHalfOpen: Reflect.get(args[0], 'allowHalfOpen'),\n },\n callback,\n ]\n }\n\n throw new Error(`Invalid arguments passed to net.connect: ${args}`)\n}\n","import net from 'node:net'\n\n/**\n * Write the given pending data to the socket using its public\n * \"write()\" method. Unlike direct \"_writeGeneric()\" calls, public\n * writes go through the \"Writable\" queue that only dispatches the\n * next write once the previous one completes. TLS sockets rely on\n * that serialization: their \"TLSWrap\" handle supports a single\n * write in flight and crashes the process with a native\n * \"Assertion failed: !current_write_\" abort when writes overlap\n * (e.g. multiple direct \"_writeGeneric()\" calls issued on a\n * connecting socket replay back-to-back on \"connect\").\n */\nexport function writePendingData(\n socket: net.Socket,\n data: NonNullable<net.Socket['_pendingData']>,\n encoding: BufferEncoding,\n callback?: (error?: Error | null) => void\n): void {\n if (Array.isArray(data)) {\n for (let index = 0; index < data.length; index++) {\n const entry = data[index]\n const isLastEntry = index === data.length - 1\n\n /**\n * @note Per-entry callbacks are intentionally ignored, the same\n * way \"writevGeneric()\" only honors the batch-level callback.\n */\n if (isLastEntry) {\n socket.write(entry.chunk, entry.encoding, callback)\n } else {\n socket.write(entry.chunk, entry.encoding)\n }\n }\n\n return\n }\n\n socket.write(data, encoding, callback)\n}\n\nexport function unwrapPendingData(\n data: NonNullable<net.Socket['_pendingData']>,\n callback: (\n chunk: string | Buffer,\n encoding?: BufferEncoding,\n callback?: (error?: Error | null) => void\n ) => void\n) {\n if (Array.isArray(data)) {\n for (const entry of data) {\n callback(entry.chunk, entry.encoding, entry.callback)\n }\n } else {\n callback(data)\n }\n}\n","import type tls from 'node:tls'\n\n/**\n * Returns the original options the given TLS socket was created with.\n * The original `tls.connect()` stores them on the socket instance\n * under an internal symbol before connecting its transport.\n * @see https://github.com/nodejs/node/blob/3178a762d6a2b1a37b74f02266eea0f3d86603f1/lib/_tls_wrap.js#L1690\n */\nexport function getTlsConnectOptions(\n socket: tls.TLSSocket\n): tls.ConnectionOptions | undefined {\n const kConnectOptions = Object.getOwnPropertySymbols(socket).find(\n (symbol) => {\n return symbol.description === 'connect-options'\n }\n )\n\n if (kConnectOptions == null) {\n return undefined\n }\n\n return Reflect.get(socket, kConnectOptions)\n}\n","import net from 'node:net'\nimport { NetworkConnectionOptions } from './normalize-net-connect-args'\n\nexport function getAddressInfoByConnectionOptions(\n options?: NetworkConnectionOptions\n): ReturnType<net.Socket['address']> {\n if (options == null) {\n return {}\n }\n\n const isIPv6 = options.family === 6 || net.isIPv6(options.host || '')\n\n return {\n address: isIPv6 ? '::1' : '127.0.0.1',\n /**\n * @note Coerce the port to a number. Connection options may\n * describe it as a string (e.g. when created from a URL), while\n * the address info always reports a numeric port.\n */\n port: Number(options.port) || (options.protocol === 'https:' ? 443 : 80),\n family: isIPv6 ? 'IPv6' : 'IPv4',\n }\n}\n\n/**\n * Get the local address info for the given connection options.\n * This describes the client-side end of the connection: the socket\n * is bound to the loopback interface and an ephemeral port, the same\n * way the operating system binds an outgoing connection.\n */\nexport function getLocalAddressInfoByConnectionOptions(\n options?: NetworkConnectionOptions\n): ReturnType<net.Socket['address']> {\n if (options == null) {\n return {}\n }\n\n const isIPv6 = options.family === 6 || net.isIPv6(options.host || '')\n\n return {\n address: options.localAddress || (isIPv6 ? '::1' : '127.0.0.1'),\n port: options.localPort || getEphemeralPort(),\n family: isIPv6 ? 'IPv6' : 'IPv4',\n }\n}\n\n/**\n * Get a random port from the ephemeral range (IANA: 49152-65535),\n * the range the operating system draws from when binding an\n * outgoing connection.\n */\nfunction getEphemeralPort(): number {\n return 49152 + Math.floor(Math.random() * (65535 - 49152 + 1))\n}\n","import net from 'node:net'\nimport tls from 'node:tls'\nimport { invariant } from 'outvariant'\nimport { toBuffer } from '../../utils/buffer-utils'\nimport { createLogger } from '../../utils/logger'\nimport { unwrapPendingData, writePendingData } from './utils/flush-writes'\nimport { NetworkConnectionOptions } from './utils/normalize-net-connect-args'\nimport { TlsConnectionOptions } from './utils/normalize-tls-connect-args'\nimport { getTlsConnectOptions } from './utils/get-tls-connect-options'\nimport {\n getAddressInfoByConnectionOptions,\n getLocalAddressInfoByConnectionOptions,\n} from './utils/address-info'\n\nconst kListenerWrap = Symbol('kListenerWrap')\nexport const kRawSocket = Symbol('kRawSocket')\nexport const kPatched = Symbol('kPatched')\n\nconst logger = createLogger('socket')\n\n// Internally, Node.js represents the result of various operations\n// by the number they return: 0 (error), 1 (success).\ntype OperationStatus = 0 | 1\n\ndeclare module 'node:net' {\n interface Socket {\n [kPatched]?: boolean\n _httpMessage?: object | null\n _pendingData:\n | string\n | Buffer\n | Array<{\n chunk: string | Buffer\n encoding?: BufferEncoding\n callback?: (error?: Error | null) => void\n }>\n | null\n _pendingEncoding: BufferEncoding | ''\n _bytesDispatched: number\n _writeGeneric(\n writev: boolean,\n data: NonNullable<net.Socket['_pendingData']>,\n encoding: BufferEncoding,\n callback?: (error?: Error | null) => void\n ): void\n _handle: TcpHandle\n _start: () => void\n _unrefTimer: () => void\n }\n}\n\ndeclare module 'node:tls' {\n interface TLSSocket {\n _handle: TcpHandle & {\n start: () => void\n onhandshakedone: () => void\n onnewsession: (sessionId: unknown, session: Buffer) => void\n getSession: () => Buffer\n isSessionReused: () => boolean\n getServername: () => string\n getALPNNegotiatedProtocol: () => string | false\n getCipher: () => { name: string; standardName: string; version: string }\n getEphemeralKeyInfo: () => tls.EphemeralKeyInfo\n verifyError: () => void\n }\n }\n}\n\nexport interface TcpHandle {\n open: (fd: unknown) => OperationStatus\n connect: (request: TcpWrap, address: string, port: number) => void\n connect6: (request: TcpWrap, address: string, port: number) => void\n listen: (backlog: number) => OperationStatus\n onconnection?: () => void\n getpeername?: (\n addressInfo: ReturnType<net.Socket['address']>\n ) => OperationStatus\n getsockname?: (\n addressInfo: ReturnType<net.Socket['address']>\n ) => OperationStatus\n reading: boolean\n onread: () => void\n readStart: () => void\n readStop: () => void\n bytesRead: number\n bytesWritten: number\n ref?: () => void\n unref?: () => void\n hasRef?: () => boolean\n fchmod: (mode: number) => void\n setBlocking: (blocking: boolean) => OperationStatus\n setNoDelay?: (noDelay: boolean) => void\n setKeepAlive?: (keepAlive: boolean, initialDelay: number) => void\n setTypeOfService?: (tos: number) => OperationStatus\n shutdown: (reqest: unknown /* ShutdownWrap */) => OperationStatus\n close: () => void\n\n _parent?: TcpHandle\n}\n\nexport interface TcpWrap {\n oncomplete: (\n status: OperationStatus,\n owner: TcpHandle,\n request: TcpWrap,\n readable?: boolean,\n writable?: boolean\n ) => void\n}\n\n/**\n * Create a proxy `net.Socket` instance that represents the intercepted socket server-side.\n * This is the reference exposed as `socket` in the connection listener. This proxy allows\n * the user to interact with `socket` from the server's perspective (e.g. `socket.write()`\n * on the server translates to the `socket.push()` on the client).\n */\ninterface PendingServerWrite {\n chunk: string | Uint8Array\n encoding?: BufferEncoding\n callback?: (error?: Error) => void\n}\n\ninterface PendingServerEnd {\n chunk?: string | Uint8Array\n encoding?: BufferEncoding\n callback?: () => void\n}\n\nfunction toServerSocket<T extends net.Socket>(socket: T): T {\n /**\n * The server-side write buffer. Pushing data to the client honors\n * the client's read backpressure: once \"socket.push()\" reports a\n * full buffer, subsequent server writes queue here and flush when\n * the client reads again (\"_read\"). This mirrors how a real server\n * cannot write faster than the client consumes.\n */\n const pendingWrites: Array<PendingServerWrite> = []\n let pendingEnd: PendingServerEnd | undefined\n let isBackpressured = false\n let isFlushScheduled = false\n\n const flushPendingWrites = (): boolean => {\n /**\n * @note The mocked connection is not established yet. Flush once\n * it is, the same way a real server cannot write to a client\n * that has not connected.\n */\n if (socket.connecting) {\n isBackpressured = true\n\n if (!isFlushScheduled) {\n isFlushScheduled = true\n socket.once('ready', () => {\n isFlushScheduled = false\n flushPendingWrites()\n })\n }\n\n return false\n }\n\n while (pendingWrites.length > 0) {\n const nextWrite = pendingWrites.shift()!\n\n // Receiving mocked data is socket activity: refresh the client's\n // idle timer the same way its own reads would.\n socket._unrefTimer()\n\n const canPushMore = socket.push(\n toBuffer(nextWrite.chunk, nextWrite.encoding),\n nextWrite.encoding\n )\n nextWrite.callback?.()\n\n if (!canPushMore) {\n isBackpressured = true\n return false\n }\n }\n\n const wasBackpressured = isBackpressured\n isBackpressured = false\n\n if (pendingEnd) {\n const finalEnd = pendingEnd\n pendingEnd = undefined\n\n // Deliver the final chunk passed to \"end(chunk)\", if any.\n if (finalEnd.chunk != null) {\n socket.push(toBuffer(finalEnd.chunk, finalEnd.encoding), finalEnd.encoding)\n }\n\n socket.push(null)\n finalEnd.callback?.()\n }\n\n if (wasBackpressured) {\n socket.emit('internal:drain')\n }\n\n return true\n }\n\n /**\n * @note \"_read\" is the client asking for more data. Flush the\n * buffered server writes so the delivery resumes as the client\n * reads, completing the backpressure loop.\n */\n const realRead = socket._read.bind(socket)\n socket._read = (size: number) => {\n realRead(size)\n\n if (pendingWrites.length > 0 || pendingEnd != null || isBackpressured) {\n flushPendingWrites()\n }\n }\n\n return new Proxy(socket, {\n get: (target, property, receiver) => {\n const getRealValue = () => {\n return Reflect.get(target, property, receiver)\n }\n\n if (\n property === 'on' ||\n property === 'addListener' ||\n property === 'once' ||\n property === 'prependListener' ||\n property === 'prependOnceListener'\n ) {\n const realAddListener = getRealValue() as net.Socket['addListener']\n\n return (event: any, listener: (...args: Array<unknown>) => void) => {\n if (event === 'data') {\n const listenerWrap = (chunk: any, encoding?: BufferEncoding) => {\n listener(toBuffer(chunk, encoding))\n }\n\n Object.defineProperty(listener, kListenerWrap, {\n enumerable: false,\n writable: false,\n value: listenerWrap,\n })\n\n /**\n * @note Subscribe using the same method (e.g. \"once\") so its\n * listener semantics apply to the internal channel too.\n */\n Reflect.apply(realAddListener, target, [\n 'internal:write',\n listenerWrap,\n ])\n\n return target\n }\n\n /**\n * @note The \"drain\" event on the server socket signals the\n * flush of the server-side write buffer. It is routed through\n * an internal channel so it does not clash with the \"drain\"\n * event of the underlying client socket.\n */\n if (event === 'drain') {\n Reflect.apply(realAddListener, target, ['internal:drain', listener])\n return target\n }\n\n return realAddListener.call(target, event, listener)\n }\n }\n\n if (property === 'off' || property === 'removeListener') {\n const realRemoveListener =\n getRealValue() as net.Socket['removeListener']\n\n return (event: string, listener: any) => {\n if (event === 'data') {\n const listenerWrap = listener[kListenerWrap]\n\n if (listenerWrap) {\n // The wrap is subscribed to the internal channel,\n // not the \"data\" event (see the listener proxy above).\n return realRemoveListener.call(\n target,\n 'internal:write',\n listenerWrap\n )\n }\n }\n\n if (event === 'drain') {\n return realRemoveListener.call(target, 'internal:drain', listener)\n }\n\n return realRemoveListener.call(target, event, listener)\n }\n }\n\n // Push data to the client socket when server \"socket.write()\" is called.\n if (property === 'write') {\n return ((chunk, encoding, callback) => {\n if (typeof encoding === 'function') {\n callback = encoding\n encoding = undefined\n }\n\n pendingWrites.push({ chunk, encoding, callback })\n\n /**\n * @note Do not push more data to a client that is not\n * reading. The write stays buffered until the client reads\n * again, and \"drain\" signals the flush.\n */\n if (isBackpressured) {\n return false\n }\n\n return flushPendingWrites()\n }) as net.Socket['write']\n }\n\n // Translate server-side \"socket.end()\" to client-sode \"socket.push(null)\".\n if (property === 'end') {\n return ((...args: Parameters<net.Socket['end']>): net.Socket => {\n const callback = args[args.length - 1]\n const chunk = typeof args[0] === 'function' ? undefined : args[0]\n const encoding = typeof args[1] === 'string' ? args[1] : undefined\n\n /**\n * @note The end-of-stream is delivered once the buffered\n * writes flush so the client never observes the EOF before\n * the data that preceded it.\n */\n pendingEnd = {\n chunk,\n encoding,\n callback: typeof callback === 'function' ? callback : undefined,\n }\n flushPendingWrites()\n\n /**\n * @note Do not end the client socket's writable side.\n * The server ending the connection only signals EOF to the\n * client (the client may keep writing on half-open sockets).\n */\n return target\n }) as net.Socket['end']\n }\n\n return getRealValue()\n },\n })\n}\n\nexport abstract class SocketController {\n static PENDING = 0 as const\n static CLAIMED = 1 as const\n static PASSTHROUGH = 2 as const\n\n public readyState:\n | typeof SocketController.PENDING\n | typeof SocketController.CLAIMED\n | typeof SocketController.PASSTHROUGH\n\n #awaitedVerdicts = 0\n\n private [kRawSocket]: net.Socket\n\n constructor(socket: net.Socket) {\n this[kRawSocket] = socket\n // Mark this socket as patched so socket-related patches\n // (e.g. the \"destroyed\" getter) can tell it apart from\n // the sockets created before the interception was applied.\n socket[kPatched] = true\n this.readyState = SocketController.PENDING\n }\n\n /**\n * Claim this socket. Once claimed, the connection attempt succeeds\n * regardless of the requested host and the interceptor becomes the\n * mocked server for this connection.\n */\n public claim(): void {\n invariant(\n this.readyState === SocketController.PENDING,\n 'Failed to claim a socket connection: already handled (%s)',\n this.readyState\n )\n\n this.readyState = SocketController.CLAIMED\n }\n\n /**\n * Establish this socket connection as-is.\n */\n public passthrough(): void {\n invariant(\n this.readyState === SocketController.PENDING,\n 'Failed to passthrough a socket connection: already handled (%s)',\n this.readyState\n )\n\n this.readyState = SocketController.PASSTHROUGH\n }\n\n /**\n * Await a verdict on this connection from the given number of\n * subscribers. A connection nobody awaits to inspect (or one that\n * every awaited subscriber has declined) is passed through as-is.\n * This makes \"unclaimed after everyone declined\" a state owned by\n * the controller instead of the individual subscribers.\n */\n public awaitVerdicts(count: number): void {\n this.#awaitedVerdicts = count\n\n if (this.#awaitedVerdicts === 0) {\n this.passthrough()\n }\n }\n\n /**\n * Decline this socket connection. Declining means the subscriber\n * has inspected the connection and will not handle it (e.g. the\n * traffic is not of the protocol that subscriber implements).\n * Once every awaited subscriber declines, the connection is\n * passed through as-is.\n */\n public decline(): void {\n if (this.readyState !== SocketController.PENDING) {\n return\n }\n\n this.#awaitedVerdicts -= 1\n\n if (this.#awaitedVerdicts <= 0) {\n /**\n * @note Defer the passthrough so it never transitions this\n * controller in the middle of a client write. Declines are\n * issued while the written data is being pushed to the server\n * socket, and a synchronous transition would race the write's\n * own bookkeeping (e.g. re-buffering the write after a reset\n * at an exchange boundary).\n */\n process.nextTick(() => {\n if (\n this.readyState === SocketController.PENDING &&\n !this[kRawSocket].destroyed\n ) {\n this.passthrough()\n }\n })\n }\n }\n}\n\nexport type FlushPendingDataFunction = (\n data: NonNullable<net.Socket['_pendingData']>,\n encoding: BufferEncoding | undefined,\n callback: (data: NonNullable<net.Socket['_pendingData']>) => void\n) => void\n\ntype CorkedReadEvent =\n | { type: 'data'; chunk: Buffer }\n | { type: 'end' }\n | { type: 'close'; hadError: boolean }\n\nexport class TcpSocketController extends SocketController {\n public serverSocket: net.Socket\n\n protected pendingConnection: PromiseWithResolvers<[TcpWrap, TcpHandle]>\n\n #connectionOptions?: NetworkConnectionOptions\n #retargetedConnectionOptions?: NetworkConnectionOptions &\n net.SocketConnectOpts\n #realWriteGeneric: net.Socket['_writeGeneric']\n #passthroughSocket: net.Socket | null = null\n #bufferedWrites: Array<Parameters<net.Socket['_writeGeneric']>> = []\n #readsCorked = false\n #corkedReads: Array<CorkedReadEvent> = []\n #realHandleSwapped = false\n #resetScheduled = false\n #clientCloseEmitted = false\n #clientEndPushed = false\n #connectEmulated = false\n\n constructor(\n protected readonly socket: net.Socket,\n protected readonly createConnection: () => net.Socket,\n connectionOptions?: NetworkConnectionOptions\n ) {\n super(socket)\n\n /**\n * @note Plain TCP sockets capture the connection options from the\n * \"socket.connect()\" proxy below. TLS sockets carry additional\n * TLS-level options that never pass through \"socket.connect()\",\n * so those are provided explicitly (see \"TlsSocketController\").\n */\n this.#connectionOptions = connectionOptions\n\n // Implement the read method to prevent the \"Error: read ENOTCONN\" errors on non-existing hosts.\n this.socket._read = () => {\n /**\n * @note Resume the passthrough socket when the consumer asks for\n * more data. Node.js calls \"_read()\" once the consumer drains the\n * read buffer (e.g. after \"resume()\"). The passthrough socket may\n * have been paused when the consumer's buffer got full, and this\n * is the only signal to continue reading.\n */\n this.#passthroughSocket?.resume()\n }\n\n // Store the unpatched write method so passthrough writes can\n // delegate to it once the socket receives the real handle.\n this.#realWriteGeneric = this.socket._writeGeneric\n this.#bufferedWrites = []\n\n this.socket._writeGeneric = (...args) => {\n this.#handleWrite(args)\n }\n\n this.socket.connect = new Proxy(this.socket.connect, {\n apply: (target, thisArg, args) => {\n logger.verbose('socket.connect() %o', args)\n\n this.#connectionOptions = args[0]\n\n /**\n * @note Do not bind the intercepted socket to the requested\n * local address/port. Binding reserves the port for real, and\n * the passthrough connection (created with the original options)\n * would then bind the same port again, resulting in a conflict.\n * The requested values are still reflected in the address info\n * of a claimed socket (see \"claim()\").\n */\n if (\n args[0] != null &&\n typeof args[0] === 'object' &&\n (args[0].localAddress != null || args[0].localPort != null)\n ) {\n args[0] = { ...args[0], localAddress: undefined, localPort: undefined }\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n\n /**\n * @note A single socket can be reused for connections to the same host.\n * When one connection ends, the Agent frees the socket, then uses it\n * to write the next request's HTTP message immediately. Use the \"free\"\n * event to transition the controller into the pending state so the\n * next exchange is handled anew.\n */\n socket\n .on('free', () => {\n logger.verbose('client socket freed!')\n this.reset()\n })\n .on('close', () => {\n logger.verbose('client socket closed!')\n this.#clientCloseEmitted = true\n\n /**\n * @note Destroy the passthrough socket, if any. The client\n * socket is done, and a passthrough connection left open would\n * linger until the server closes it (or error unhandled if it\n * is still connecting).\n */\n this.#passthroughSocket?.destroy()\n this.#passthroughSocket = null\n\n this.#bufferedWrites = []\n this.#readsCorked = false\n this.#corkedReads = []\n })\n\n this.serverSocket = toServerSocket(this.socket)\n\n this.pendingConnection = Promise.withResolvers()\n this.#reset()\n }\n\n /**\n * Reset this controller to the pending state so the next exchange\n * on this socket can be handled anew. This is meant for kept-alive\n * sockets that are reused for multiple exchanges by clients that\n * don't emit the \"free\" event on the socket (e.g. Undici).\n *\n * Providing connection options retargets this connection: the\n * exchanges that follow belong to the given target (e.g. the\n * authority of an established \"CONNECT\" tunnel). An unclaimed\n * exchange then passes through to that target instead of the\n * originally dialed one, and a claimed exchange reports it as the\n * peer. The verdict count is deliberately not re-armed: subscribers\n * that declined this connection's protocol stay declined across\n * the exchanges, retargeted or not.\n */\n public reset(\n connectionOptions?: NetworkConnectionOptions & net.SocketConnectOpts\n ): void {\n if (connectionOptions != null) {\n this.#retargetedConnectionOptions = connectionOptions\n this.#connectionOptions = connectionOptions\n\n /**\n * @note The passthrough connection to the original target, if\n * any, cannot serve the retargeted exchanges. Detach its\n * forwarding listeners before destroying it so its teardown is\n * not mistaken for the client connection's own (e.g. its \"close\"\n * must not close the client socket).\n */\n if (this.#passthroughSocket) {\n this.#passthroughSocket\n .removeListener('connect', this.#onRealSocketConnect)\n .removeListener(\n 'connectionAttemptFailed',\n this.#onRealSocketConnectionAttemptFailed\n )\n .removeListener(\n 'connectionAttemptTimeout',\n this.#onRealSocketConnectionAttemptTimeout\n )\n .removeListener('data', this.#onRealSocketData)\n .removeListener('error', this.#onRealSocketError)\n .removeListener('end', this.#onRealSocketEnd)\n .removeListener('close', this.#onRealSocketClose)\n .destroy()\n\n this.#passthroughSocket = null\n\n /**\n * @note The handle swapped in from the destroyed connection,\n * if any, no longer carries this socket's traffic. Treat the\n * socket as not swapped so the retargeted passthrough writes\n * directly to the new connection until its own handle swap.\n */\n this.#realHandleSwapped = false\n }\n }\n\n /**\n * @note Only settled (claimed or passed-through) sockets need a reset.\n * Resetting a pending socket again would discard the writes already\n * buffered for the next exchange (e.g. the Agent \"free\" event firing\n * after the parser has reset this controller at a message boundary).\n */\n if (this.readyState === SocketController.PENDING) {\n return\n }\n\n this.#reset()\n }\n\n /**\n * Schedule a reset of this controller to happen right before the\n * next client write. The consumer signals the boundary of the\n * current exchange (e.g. an HTTP message boundary) the moment it is\n * parsed — mid-delivery of the exchange's final chunk — when an\n * immediate reset would discard that chunk. Deferring the reset to\n * the next write lets the current exchange settle as-is while the\n * next exchange's first write already buffers for a new verdict\n * (instead of following the previous one, e.g. leaking to the\n * passthrough connection).\n */\n public scheduleReset(): void {\n this.#resetScheduled = true\n }\n\n #reset(): void {\n logger.verbose('resetting the socket...')\n\n this.#resetScheduled = false\n this.readyState = SocketController.PENDING\n this.pendingConnection = Promise.withResolvers()\n this.#bufferedWrites = []\n this.#connectEmulated = false\n\n // Release the pending data of the previous exchange, if any,\n // so kept-alive sockets do not retain every written payload.\n this.socket._pendingData = null\n this.socket._pendingEncoding = ''\n\n const wrapHandle = (handle: TcpHandle) => {\n this.pendingConnection.promise.then(() => {\n logger.verbose('connection request resolved!', this.readyState)\n\n process.nextTick(() => {\n /**\n * @note If by this point the socket hasn't been handled,\n * is still connecting, doesn't have any writes buffered,\n * and has a \"connect\" listener, assume it's the \"write after connect\"\n * scenario (e.g. undici). In that case, auto-claim the socket to\n * transition to the connected state appropriately to its handle.\n */\n if (\n this.readyState === SocketController.PENDING &&\n this.socket.connecting &&\n this.#bufferedWrites.length === 0 &&\n this.socket.listenerCount('connect') > 0\n ) {\n logger.verbose(\n 'assume connect->write socket, calling \"connect\" listeners...'\n )\n this.emulateConnect()\n }\n })\n })\n\n /**\n * Remove the \"setTypeOfService\" from the handle, if present (Node.js v24+).\n * Removing it has no effect on the socket but prevents the \"setTypeOfService EBADF\" error.\n * @see https://github.com/nodejs/node/blob/69a970f76814d40f55cf162d0cc3632fe8a7e599/lib/net.js#L661\n * @see https://github.com/nodejs/undici/blob/bf684f7de01616708a33a5d1c092177622394442/lib/dispatcher/client-h1.js#L1136\n */\n if (handle.setTypeOfService) {\n handle.setTypeOfService = undefined\n }\n\n handle.connect = handle.connect6 = (request) => {\n logger.verbose('handle.connect()')\n this.pendingConnection.resolve([request, handle])\n }\n\n logger.verbose('socket handle wrapped! waiting for connection request...')\n }\n\n if (this.socket._handle) {\n wrapHandle(this.socket._handle)\n } else {\n this.socket.prependOnceListener('connectionAttempt', () => {\n wrapHandle(this.socket._handle)\n })\n }\n }\n\n /**\n * Handle a write performed on the client socket. Installed once as\n * \"_writeGeneric\", this is the single write path for every controller\n * state, dispatching on \"readyState\".\n */\n #handleWrite(args: Parameters<net.Socket['_writeGeneric']>): void {\n const data = args[1]\n\n logger.verbose('socket write (state: %d) %o', this.readyState, args)\n\n /**\n * @note A scheduled reset marks the boundary of the previous\n * exchange (see \"scheduleReset\"). This write is the first one past\n * the boundary; reset before dispatching so it opens the next\n * exchange instead of following the previous exchange's verdict.\n */\n if (this.#resetScheduled) {\n this.reset()\n }\n\n /**\n * @note Buffer the write BEFORE pushing the data to the server socket.\n * Handling the pushed data may transition this controller within the\n * same call stack, and each transition settles the buffered entry:\n * \"passthrough()\" flushes it to the real socket, \"claim()\" drops it,\n * and a reset at an HTTP message boundary keeps it for the next exchange.\n */\n this.#bufferedWrites.push(args)\n\n if (this.readyState === SocketController.PENDING) {\n /**\n * @note Reflect the buffered write in \"_pendingData\" so it counts\n * toward \"bytesWritten\", the same way Node.js counts the pending\n * data of a connecting socket. Flushing the buffered writes resets\n * \"_pendingData\" (see `passthrough()`).\n */\n const pendingData = Array.isArray(this.socket._pendingData)\n ? this.socket._pendingData\n : []\n\n unwrapPendingData(data, (chunk, chunkEncoding) => {\n pendingData.push({ chunk, encoding: chunkEncoding })\n })\n\n this.socket._pendingData = pendingData\n\n // The server socket will NEVER have any \"data\" listeners attached\n // on the first write because the \"connection\" interceptor event\n // emits on the next tick.\n if (this.socket.listenerCount('internal:write') === 0) {\n logger.verbose(\n 'no server data listeners, scheduling to the next tick...'\n )\n\n process.nextTick(() => {\n this.#push(data)\n })\n } else {\n this.#push(data)\n }\n } else {\n this.#push(data)\n }\n\n /**\n * Dispatch on the state observed AFTER the push since handling the\n * pushed data may have transitioned this controller synchronously.\n */\n switch (this.readyState) {\n case SocketController.PENDING: {\n /**\n * @note The write either awaits the verdict on this exchange or,\n * if the push reset this controller at a message boundary, opens\n * the next exchange (the reset cleared the buffer; re-buffer it).\n */\n if (!this.#bufferedWrites.includes(args)) {\n this.#bufferedWrites.push(args)\n }\n\n this.#acknowledgeWrite(args)\n return\n }\n\n case SocketController.CLAIMED: {\n /**\n * @note Once claimed, there's nowhere else to write chunks to.\n * The data was delivered to the server socket; complete the write\n * so the socket's writable state settles (enabling \"finish\").\n */\n this.#removeBufferedWrite(args)\n this.#acknowledgeWrite(args)\n return\n }\n\n case SocketController.PASSTHROUGH: {\n /**\n * @note A synchronous \"passthrough()\" has already flushed this\n * write (with its callback) to the real socket.\n */\n if (!this.#removeBufferedWrite(args)) {\n return\n }\n\n /**\n * @note Until the handle swap, the client socket's own handle\n * cannot carry any data (it never actually connects). Write\n * directly to the passthrough socket instead. This also prevents\n * the \"connecting\" write replay of `Socket.prototype._writeGeneric`\n * from pushing the same data to the server socket twice.\n */\n if (!this.#realHandleSwapped && this.#passthroughSocket) {\n writePendingData(this.#passthroughSocket, data, args[2], args[3])\n return\n }\n\n this.#realWriteGeneric.apply(this.socket, args)\n }\n }\n }\n\n /**\n * Complete the given write by invoking its callback. The callback is\n * then removed from the write entry so flushing that entry later\n * (e.g. on passthrough) does not invoke it twice.\n */\n #acknowledgeWrite(args: Parameters<net.Socket['_writeGeneric']>): void {\n const callback = args[3]\n\n if (typeof callback === 'function') {\n callback()\n args[3] = undefined\n }\n }\n\n #removeBufferedWrite(\n args: Parameters<net.Socket['_writeGeneric']>\n ): boolean {\n const index = this.#bufferedWrites.indexOf(args)\n\n if (index === -1) {\n return false\n }\n\n this.#bufferedWrites.splice(index, 1)\n return true\n }\n\n protected emulateConnect() {\n this.#connectEmulated = true\n\n /**\n * @note Reflect the connected state before notifying the listeners,\n * the same way Node.js does before emitting \"connect\".\n */\n Reflect.set(this.socket, 'connecting', false)\n\n /**\n * @note Invoke the raw listeners so the \"once\" wrappers get\n * consumed. This prevents listeners like the connection callback\n * from being invoked again when \"connect\" is emitted for real\n * (e.g. once the claimed connection completes).\n */\n for (const listener of this.socket.rawListeners('connect')) {\n listener.apply(this.socket)\n }\n }\n\n /**\n * Push the given data to the server socket.\n * This has no effect on the public-facing socket and is used\n * only for the interceptors to subscribe to \"socket.on('data')\"\n * before the data is actually written anywhere.\n */\n #push = (data: net.Socket['_pendingData']) => {\n if (data == null) {\n return\n }\n\n logger.verbose('server push %o', data)\n\n unwrapPendingData(data, (chunk, encoding) => {\n logger.verbose('server emitting \"data\" %o', { chunk, encoding })\n\n this.socket.emit('internal:write', chunk, encoding)\n })\n }\n\n #onRealSocketConnect = () => {\n if (!this.#passthroughSocket) {\n return\n }\n\n /**\n * @note The consumer may destroy the socket while the passthrough\n * connection is still being established. The passthrough \"connect\"\n * (I/O poll phase) can arrive before the client's \"close\" callback\n * (close phase) within the same event loop iteration. A destroyed\n * socket must not emit \"connect\"/\"ready\".\n */\n if (this.socket.destroyed) {\n this.#passthroughSocket.destroy()\n return\n }\n\n const replacedHandle = this.socket._handle\n const wasUnrefed =\n replacedHandle != null &&\n typeof replacedHandle.hasRef === 'function' &&\n !replacedHandle.hasRef()\n\n this.socket._handle = this.#passthroughSocket._handle\n this.#realHandleSwapped = true\n\n /**\n * @note Preserve the ref state across the handle swap. If the\n * consumer unrefed the socket while it was connecting, the swapped\n * handle must not hold the process alive either.\n */\n if (wasUnrefed) {\n this.socket._handle.unref?.()\n }\n\n /**\n * @note Close the replaced handle. Nothing references it past this\n * point, and left open, it keeps the process alive indefinitely.\n * For TLS sockets, the replaced handle is a TLSWrap; close its\n * underlying transport too (closing the wrap alone does not close\n * the TCP handle it sits on).\n */\n if (replacedHandle != null) {\n replacedHandle.close()\n replacedHandle._parent?.close()\n }\n\n Reflect.set(this.socket, 'connecting', false)\n\n /**\n * @note Read the remote address info once so it gets cached on the\n * socket. The passthrough socket controls the swapped handle and may\n * close it at any point (e.g. once the server ends the connection),\n * while Node.js keeps serving the cached info for sockets that\n * have connected. Reading must happen after the socket is no longer\n * connecting (the info of connecting sockets is never cached).\n */\n void this.socket.remoteAddress\n\n this.socket.emit('connect')\n this.socket.emit('ready')\n }\n\n #onRealSocketConnectionAttemptFailed = (\n address: string,\n port: number,\n family: number,\n error: Error\n ) => {\n this.socket.emit('connectionAttemptFailed', address, port, family, error)\n }\n\n #onRealSocketConnectionAttemptTimeout = (\n address: string,\n port: number,\n family: number\n ) => {\n this.socket.emit('connectionAttemptTimeout', address, port, family)\n }\n\n #onRealSocketData = (data: Buffer) => {\n logger.verbose('real socket \"data\" event %o', data)\n\n /**\n * @note Receiving data is socket activity. Refresh the idle timer\n * of the client socket the same way its own reads would\n * (\"socket.setTimeout()\" must not fire during an active transfer).\n * The data arrives on the real socket, which only refreshes the\n * real socket's timer.\n */\n this.socket._unrefTimer()\n\n if (this.#readsCorked) {\n logger.verbose('reads are corked, buffering the data...')\n this.#corkedReads.push({ type: 'data', chunk: data })\n return\n }\n\n if (!this.socket.push(data)) {\n logger.verbose(\n 'client socket forbade more pushes, pausing the passthrough socket...'\n )\n this.#passthroughSocket?.pause()\n }\n }\n\n #onRealSocketError = (error: Error) => {\n logger.verbose('real socket \"error\" event %o', error)\n\n if (this.socket.destroyed) {\n logger.verbose(\n 'real socket errored but client socket already destroyed, skipping...'\n )\n return\n }\n\n logger.verbose('real socket errored, forwarding %o', error)\n\n this.socket.destroy(error)\n\n // The handle swap in passthrough (this.socket._handle = realSocket._handle)\n // breaks Node's internal close machinery—destroy() emits \"error\" but never\n // emits \"close\". Consumers like Undici wait for \"close\" to finalize the\n // request, so we must emit it manually.\n // Before the swap (e.g. a failed connection attempt), the client socket\n // emits \"close\" on its own, and emitting here would duplicate it.\n if (this.#realHandleSwapped) {\n process.nextTick(() => this.socket.emit('close', true))\n }\n }\n\n #onRealSocketEnd = () => {\n // Receiving the end-of-stream is a read, the same as data.\n this.socket._unrefTimer()\n\n if (this.#readsCorked) {\n this.#corkedReads.push({ type: 'end' })\n return\n }\n\n this.#clientEndPushed = true\n this.socket.push(null)\n }\n\n #onRealSocketClose = (hadError: boolean) => {\n /**\n * @note The connection is fully closed and the swapped handle\n * cannot shut down anymore. Report a synchronous shutdown so the\n * automatic \"end()\" of a half-closed socket (\"allowHalfOpen: false\")\n * finishes without errors once the consumer reads the end-of-stream.\n */\n if (this.#realHandleSwapped && this.socket._handle) {\n this.socket._handle.shutdown = () => 1\n }\n\n if (this.#readsCorked) {\n this.#corkedReads.push({ type: 'close', hadError })\n return\n }\n\n // The client socket already emitted \"close\" (e.g. it was destroyed\n // with an error before the handle swap). Forwarding the real socket\n // \"close\" would emit it twice.\n if (this.#clientCloseEmitted) {\n return\n }\n\n // A destroyed client socket with an intact handle emits \"close\"\n // through its own machinery. Only forward the real socket \"close\"\n // when the handle swap suppressed that emission.\n if (this.socket.destroyed && !this.#realHandleSwapped) {\n return\n }\n\n this.#emitClientClose(hadError)\n }\n\n /**\n * Emit the \"close\" event on the client socket, honoring the order\n * of the socket teardown events.\n * @note The client may be paused with the received data (and the\n * end-of-stream) still buffered. Node.js never emits \"close\" before\n * \"end\" on a gracefully closed connection: the teardown waits until\n * the consumer reads the buffered data.\n */\n #emitClientClose(hadError: boolean): void {\n if (\n this.#clientEndPushed &&\n !this.socket.readableEnded &&\n !this.socket.destroyed\n ) {\n let closeDelivered = false\n const deliverClose = (hadErrorOverride?: boolean) => {\n if (closeDelivered) {\n return\n }\n closeDelivered = true\n\n process.nextTick(() => {\n if (!this.#clientCloseEmitted) {\n this.socket.emit('close', hadErrorOverride ?? hadError)\n }\n })\n }\n\n this.socket.once('end', () => {\n deliverClose()\n })\n\n /**\n * @note The consumer may also destroy the socket before reading\n * the buffered data. Node.js still emits \"close\" for such\n * sockets, but the destroy machinery of a socket with a swapped\n * (already closed) handle never completes. Deliver \"close\" here.\n */\n const realDestroy = this.socket._destroy\n this.socket._destroy = (error, callback) => {\n deliverClose(error != null)\n return realDestroy.call(this.socket, error, callback)\n }\n return\n }\n\n this.socket.emit('close', hadError)\n }\n\n #onMockSocketDrain = () => {\n logger.verbose('client socket drained!')\n this.#passthroughSocket?.resume()\n }\n\n /**\n * Forward the client's half-close to the passthrough socket.\n * The client's writable side may finish before the real handle is\n * swapped in (\"_final\" of a connected client runs against the mock\n * handle), leaving the FIN unsent. Once the handle is swapped, the\n * client's own shutdown reaches the real connection natively.\n */\n #forwardClientFinish = () => {\n if (!this.#realHandleSwapped) {\n this.#passthroughSocket?.end()\n }\n }\n\n /**\n * Suspend forwarding of the passthrough socket events (\"data\", \"end\", \"close\")\n * to the client socket. The events are buffered in order until `uncorkReads()`\n * is called. This allows the consumer to delay the delivery of the original\n * response to the client (e.g. until its own asynchronous logic settles).\n *\n * @note Pausing the client socket is not enough to delay the delivery.\n * Consumers like Undici read the pushed data from a paused socket\n * directly via `socket.read()`, which is unaffected by `socket.pause()`.\n */\n public corkReads(): void {\n this.#readsCorked = true\n }\n\n /**\n * Resume forwarding of the passthrough socket events to the client socket,\n * replaying any events buffered while the reads were corked.\n */\n public uncorkReads(): void {\n if (!this.#readsCorked) {\n return\n }\n\n this.#readsCorked = false\n\n for (const corkedRead of this.#corkedReads.splice(0)) {\n switch (corkedRead.type) {\n case 'data': {\n if (!this.socket.push(corkedRead.chunk)) {\n logger.verbose(\n 'client socket forbade more pushes, pausing the passthrough socket...'\n )\n this.#passthroughSocket?.pause()\n }\n break\n }\n\n case 'end': {\n this.#clientEndPushed = true\n this.socket.push(null)\n break\n }\n\n case 'close': {\n this.#emitClientClose(corkedRead.hadError)\n break\n }\n }\n }\n }\n\n public claim(): void {\n super.claim()\n\n /**\n * @note The client may destroy the socket before the connection\n * is claimed (e.g. abort a request in-flight). There is no\n * connection to mock then, and the destroyed socket has no handle.\n */\n if (this.socket.destroyed) {\n logger.verbose('socket already destroyed, skipping claim...')\n return\n }\n\n /**\n * @note Skip already connected sockets (e.g. kept-alive sockets\n * reused for the next exchange). Sockets with an emulated \"connect\"\n * only appear connected and must still complete the mock connection.\n */\n if (!this.socket.connecting && !this.#connectEmulated) {\n logger.verbose('socket already connected, skipping claim...')\n return\n }\n\n logger.verbose('-> claim!')\n\n /**\n * @note Reflect the local end of the claimed socket, the same way\n * the operating system reports the bound address of an outgoing\n * connection via \"socket.address()\"/\"localAddress\"/\"localPort\".\n * Patching the handle also prevents Node.js from handling the\n * \"getsockname\" errors of the never-connected raw handle.\n * @see https://github.com/nodejs/node/blob/13eb80f3b718452213e0fc449702aefbbfe4110f/lib/net.js#L971\n */\n this.socket._handle.getsockname = (addressInfo) => {\n Object.assign(\n addressInfo,\n getLocalAddressInfoByConnectionOptions(this.#connectionOptions)\n )\n return 0\n }\n\n /**\n * @note Reflect the connection target as the peer of the claimed\n * socket, the same way a connected socket reports the server it\n * connected to via \"remoteAddress\"/\"remotePort\"/\"remoteFamily\".\n */\n this.socket._handle.getpeername = (addressInfo) => {\n Object.assign(\n addressInfo,\n getAddressInfoByConnectionOptions(this.#connectionOptions)\n )\n return 0\n }\n\n this.#bufferedWrites = []\n\n // Release the buffered write payloads. They were already delivered\n // to the server socket, and there is nowhere else to flush them.\n this.socket._pendingData = null\n this.socket._pendingEncoding = ''\n\n this.pendingConnection.promise.then(([request, handle]) => {\n logger.verbose('connection request resolved, mocking the connection...')\n\n /**\n * @note \"afterConnect\" asserts that the socket is connecting.\n * Restore the flag if the connect was emulated earlier (emulation\n * flips it so its listeners observe a connected socket).\n * \"afterConnect\" itself sets it back to false.\n */\n if (this.#connectEmulated) {\n Reflect.set(this.socket, 'connecting', true)\n }\n\n /**\n * @see https://github.com/nodejs/node/blob/9cd6630870b776e96c5cf0ac68c31e2f46df3835/lib/net.js#L1142\n */\n request.oncomplete(0, handle, request, true, true)\n })\n }\n\n public passthrough(flushPendingData?: FlushPendingDataFunction): net.Socket {\n super.passthrough()\n\n logger.verbose('-> passthrough!')\n\n const createRealSocket = () => {\n const realSocket = this.#retargetedConnectionOptions\n ? this.#createRetargetedConnection(this.#retargetedConnectionOptions)\n : this.createConnection()\n\n // Mark the passthrough socket as patched so it's exempt from\n // the unpatched socket detection (it never enters agent pools,\n // but this skips the detection cost on its every \"destroyed\" read).\n realSocket[kPatched] = true\n\n if (this.socket.timeout != null) {\n realSocket.setTimeout(this.socket.timeout)\n }\n\n return realSocket\n }\n\n // If keepalive, reuse the existing real socket.\n const realSocket =\n this.#passthroughSocket && !this.#passthroughSocket.destroyed\n ? this.#passthroughSocket\n : createRealSocket()\n\n if (realSocket !== this.#passthroughSocket) {\n this.#passthroughSocket = realSocket\n }\n\n if (this.#bufferedWrites.length === 0) {\n logger.verbose(\n 'passthrough with empty writes buffer (state: %d)',\n this.readyState\n )\n }\n\n /**\n * Flush any writes during the pending phase to the passthrough socket.\n * @note These are written directly on the passthrough socket to prevent\n * them from being forwarded as \"data\" events on the server (already emitted).\n */\n for (let i = 0; i < this.#bufferedWrites.length; i++) {\n const pendingWrite = this.#bufferedWrites[i]\n\n if (i === 0 && typeof flushPendingData === 'function') {\n const data = pendingWrite[1]\n const encoding = pendingWrite[2]\n flushPendingData(data, encoding, (nextData) => {\n pendingWrite[1] = nextData\n })\n }\n\n const [, data, encoding, callback] = pendingWrite\n writePendingData(realSocket, data, encoding, callback)\n }\n\n this.#bufferedWrites = []\n this.socket._pendingData = null\n this.socket._pendingEncoding = ''\n\n this.socket.address = realSocket.address.bind(realSocket)\n\n this.socket.removeListener('drain', this.#onMockSocketDrain)\n this.socket.on('drain', this.#onMockSocketDrain)\n\n realSocket\n .removeListener('connect', this.#onRealSocketConnect)\n .removeListener(\n 'connectionAttemptFailed',\n this.#onRealSocketConnectionAttemptFailed\n )\n .removeListener(\n 'connectionAttemptTimeout',\n this.#onRealSocketConnectionAttemptTimeout\n )\n .removeListener('data', this.#onRealSocketData)\n .removeListener('error', this.#onRealSocketError)\n .removeListener('end', this.#onRealSocketEnd)\n .removeListener('close', this.#onRealSocketClose)\n\n realSocket\n .once('connect', this.#onRealSocketConnect)\n .on('connectionAttemptFailed', this.#onRealSocketConnectionAttemptFailed)\n .on(\n 'connectionAttemptTimeout',\n this.#onRealSocketConnectionAttemptTimeout\n )\n .on('data', this.#onRealSocketData)\n .on('error', this.#onRealSocketError)\n .on('end', this.#onRealSocketEnd)\n .on('close', this.#onRealSocketClose)\n\n /**\n * @note Forward the client's half-close, unless the real handle\n * is already swapped in — the client's own shutdown then reaches\n * the real connection natively (see \"#forwardClientFinish\").\n */\n if (!this.#realHandleSwapped) {\n if (this.socket.writableFinished) {\n this.#forwardClientFinish()\n } else {\n this.socket.removeListener('finish', this.#forwardClientFinish)\n this.socket.once('finish', this.#forwardClientFinish)\n }\n }\n\n return realSocket\n }\n\n /**\n * Create the passthrough connection to the target this controller\n * was retargeted to (see `reset()`). The original `createConnection`\n * dials the originally requested target and cannot serve retargeted\n * exchanges.\n */\n #createRetargetedConnection(\n connectionOptions: net.SocketConnectOpts\n ): net.Socket {\n const realSocket = new net.Socket()\n\n /**\n * @note Mark the socket as patched before connecting: the patched\n * \"Socket.prototype.connect\" exempts such sockets, establishing\n * the connection for real.\n */\n realSocket[kPatched] = true\n\n return realSocket.connect(connectionOptions)\n }\n}\n\nexport class TlsSocketController extends TcpSocketController {\n /**\n * @note The TLS connection options must be provided explicitly.\n * They cannot be captured from \"socket.connect()\" like for plain\n * TCP sockets because \"tls.connect()\" fixes them at the TLS socket\n * construction, before its transport ever connects.\n */\n #tlsConnectionOptions?: TlsConnectionOptions\n\n constructor(\n protected readonly socket: tls.TLSSocket,\n protected readonly createConnection: () => tls.TLSSocket,\n tlsConnectionOptions?: TlsConnectionOptions\n ) {\n super(socket, createConnection, tlsConnectionOptions)\n\n this.#tlsConnectionOptions = tlsConnectionOptions\n\n socket.prependListener('secureConnect', () => {\n /**\n * @note Reflect the negotiated ALPN protocol from the handle that\n * completed the handshake. The socket sets \"alpnProtocol\" only in\n * its own \"_finishInit\", which never runs for passthrough\n * connections (the handshake completes on the passthrough socket\n * whose handle this socket inherits).\n */\n socket.alpnProtocol = socket._handle.getALPNNegotiatedProtocol()\n })\n }\n\n protected emulateConnect(): void {\n super.emulateConnect()\n\n // For TLS sockets, also invoke the \"secureConnect\" callbacks since some consumers,\n // like Undici, listen to those to start writing to the socket.\n for (const listener of this.socket.rawListeners('secureConnect')) {\n listener.apply(this.socket)\n }\n }\n\n public claim(): void {\n /**\n * @note The client may destroy the socket before the connection\n * is claimed. Defer to the parent class, which transitions the\n * ready state and skips the mock connection of destroyed sockets.\n */\n if (this.socket.destroyed) {\n super.claim()\n return\n }\n\n /**\n * @note Reflect that the mocked connection is not authorized.\n * There is no real peer certificate to verify. The identity check\n * itself is skipped for claimed connections (see the\n * \"isSessionReused\" mock below).\n */\n this.socket.prependOnceListener('secureConnect', () => {\n Reflect.set(this.socket, 'authorized', false)\n Reflect.set(\n this.socket,\n 'authorizationError',\n 'MOCKED_CONNECTION_NOT_VERIFIED'\n )\n })\n\n // Run this logic before the parent's class method so it executes first.\n // TLSWrap methods have to be patched before TCPWrap fires \"oncomplete\".\n const handle = this.socket._handle\n\n handle.start = () => void 0\n\n /**\n * Mock this to prevent the \"Error: Worker exited unexpectedly\" error.\n * This will trigger when \"secure\" is emitted.\n * @see https://github.com/nodejs/node/blob/bdc8131fa78089b81b74dbff467365afb6536e6a/lib/internal/tls/wrap.js#L1648\n */\n handle.verifyError = () => void 0\n\n handle.getSession = () => {\n return Buffer.from('mocked session')\n }\n\n /**\n * @note Skip the server identity check for this mocked connection.\n * Node.js runs \"options.checkServerIdentity\" in \"onConnectSecure\"\n * against the peer certificate, and a mocked connection has no\n * real peer certificate — the caller's (or the default) validation\n * would fail and destroy the socket. The check is overridden on the\n * socket's internal connect options since the emulated handshake\n * still completes through the regular \"onConnectSecure\" path.\n * @see https://github.com/nodejs/node/blob/3178a762d6a2b1a37b74f02266eea0f3d86603f1/lib/_tls_wrap.js#L1621\n */\n const realTlsConnectOptions = getTlsConnectOptions(this.socket)\n\n if (realTlsConnectOptions) {\n realTlsConnectOptions.checkServerIdentity = () => {\n return undefined\n }\n }\n\n handle.getCipher = () => {\n return {\n name: 'TLS_AES_256_GCM_SHA384',\n standardName: 'TLS_AES_256_GCM_SHA384',\n version: 'TLSv1.3',\n }\n }\n\n /**\n * Mock this to prevent a segfault on Node.js 26+. The native\n * implementation reads the negotiated group (\"SSL_get0_group_name\")\n * of a handshake that never happened. Node.js itself calls this\n * in \"onConnectSecure\" to validate the \"minDHSize\" option.\n * Reflect the ephemeral key exchange matching the mocked cipher.\n * @see https://github.com/nodejs/node/blob/3178a762d6a2b1a37b74f02266eea0f3d86603f1/lib/_tls_wrap.js#L1636\n */\n handle.getEphemeralKeyInfo = () => {\n return {\n type: 'ECDH',\n name: 'X25519',\n size: 253,\n }\n }\n\n const requestedAlpnProtocols = this.#tlsConnectionOptions?.ALPNProtocols\n\n if (\n Array.isArray(requestedAlpnProtocols) &&\n requestedAlpnProtocols.length > 0\n ) {\n const [preferredProtocol] = requestedAlpnProtocols\n\n /**\n * @note Reflect the client's preferred ALPN protocol as the\n * negotiated one. The mocked server accepts whatever the\n * client prefers.\n */\n handle.getALPNNegotiatedProtocol = () => {\n return typeof preferredProtocol === 'string' ? preferredProtocol : false\n }\n }\n\n this.socket.once('connect', () => {\n /**\n * @note A TLS 1.3 handshake derives five secrets, each reported\n * via a separate \"keylog\" event before the handshake completes.\n * Reflect them with mocked key material matching the mocked\n * cipher (SHA-384 secrets; the format is \"LABEL <client random>\n * <secret>\", each value hex-encoded).\n */\n const mockedClientRandom = '0'.repeat(64)\n const mockedSecret = '0'.repeat(96)\n const keylogLabels = [\n 'SERVER_HANDSHAKE_TRAFFIC_SECRET',\n 'EXPORTER_SECRET',\n 'SERVER_TRAFFIC_SECRET_0',\n 'CLIENT_HANDSHAKE_TRAFFIC_SECRET',\n 'CLIENT_TRAFFIC_SECRET_0',\n ]\n\n for (const keylogLabel of keylogLabels) {\n this.socket.emit(\n 'keylog',\n Buffer.from(`${keylogLabel} ${mockedClientRandom} ${mockedSecret}\\n`)\n )\n }\n\n handle.onhandshakedone()\n\n /**\n * @note A TLS 1.3 server issues two session tickets by default,\n * each emitting a separate \"session\" event on the client.\n */\n handle.onnewsession(1, Buffer.from('mocked session'))\n handle.onnewsession(2, Buffer.from('mocked session'))\n })\n\n super.claim()\n }\n\n public passthrough(\n flushPendingData?: FlushPendingDataFunction\n ): tls.TLSSocket {\n const realSocket = super.passthrough(flushPendingData) as tls.TLSSocket\n\n /**\n * @note Remove the internal \"connect\" listener added by the TLS socket.\n * Normally, that listener manages the SSL handshake. But since we're in passthrough,\n * we delegate that to the real socket. Leaving the listener on the mock socket while\n * inheriting the real socket's handle will result in the handshake performed twice, which is a no-op.\n * @see https://github.com/nodejs/node/blob/abddfc921bf2af02a04a6a5d2bca8e2d91d80958/lib/internal/tls/wrap.js#L1105\n *\n * This prevents the following error:\n * # node (vitest 4)[8686]: static void node::crypto::TLSWrap::Start(const FunctionCallbackInfo<Value> &) at ../src/crypto/crypto_tls.cc:589\n # Assertion failed: !wrap->started_\n */\n for (const connectListener of this.socket.listeners('connect')) {\n if (\n connectListener === this.socket._start ||\n ('listener' in connectListener &&\n connectListener.listener === this.socket._start)\n ) {\n this.socket.removeListener('connect', connectListener as () => void)\n }\n }\n\n realSocket\n .on('secure', () => {\n this.socket.emit('secure')\n })\n .on('session', (...args) => {\n this.socket.emit('session', ...args)\n })\n .on('keylog', (...args) => {\n this.socket.emit('keylog', ...args)\n })\n .on('OCSPResponse', (...args) => {\n this.socket.emit('OCSPResponse', ...args)\n })\n\n return realSocket\n }\n}\n","import tls from 'node:tls'\nimport {\n type NetConnectArgs,\n type NetworkConnectionOptions,\n normalizeNetConnectArgs,\n} from './normalize-net-connect-args'\n\ntype TlsConnectArgs =\n | []\n | [options: tls.ConnectionOptions, callback?: () => void]\n | [url: URL, callback?: () => void]\n | [port: number, options?: tls.ConnectionOptions, callback?: () => void]\n | [\n port: number,\n host?: string,\n options?: tls.ConnectionOptions,\n callback?: () => void,\n ]\n\nexport type TlsConnectionOptions = tls.ConnectionOptions &\n NetworkConnectionOptions\n\ntype NormalizedTlsConnectionArgs = [\n options: TlsConnectionOptions,\n callback?: () => void,\n]\n\nexport function normalizeTlsConnectArgs(\n args: TlsConnectArgs\n): NormalizedTlsConnectionArgs {\n /**\n * @note Despite incorrect type definitions, \"tls.connect()\" has all the\n * options of \"net.connect()\" and then those specific to TLS connections,\n * like \"session\" or \"socket\".\n * @see https://github.com/nodejs/node/blob/bdc8131fa78089b81b74dbff467365afb6536e6a/lib/internal/tls/wrap.js#L1615\n */\n const netConnectArgs = normalizeNetConnectArgs(args as NetConnectArgs)\n const options = netConnectArgs[0] as TlsConnectionOptions\n const callback = netConnectArgs[1]\n\n if (args[0] !== null && typeof args[0] === 'object') {\n Object.assign(options, args[0])\n } else if (args[1] !== null && typeof args[1] === 'object') {\n Object.assign(options, args[1])\n } else if (args[2] !== null && typeof args[2] === 'object') {\n Object.assign(options, args[2])\n }\n\n return callback ? [options, callback] : [options]\n}\n","import net from 'node:net'\nimport tls from 'node:tls'\nimport http from 'node:http'\nimport { TypedEvent } from 'rettime'\nimport {\n type NetworkConnectionOptions,\n normalizeNetConnectArgs,\n} from './utils/normalize-net-connect-args'\nimport {\n kPatched,\n TcpSocketController,\n TlsSocketController,\n} from './socket-controller'\nimport { normalizeTlsConnectArgs } from './utils/normalize-tls-connect-args'\nimport { getTlsConnectOptions } from './utils/get-tls-connect-options'\nimport { createLogger } from '../../utils/logger'\nimport { patchesRegistry } from '../../utils/patches-registry'\nimport { Interceptor } from '#/src/interceptor'\n\ndeclare module 'node:http' {\n interface Agent {\n /**\n * @note An undocumented method backing every agent-driven request\n * (see \"#stopReusingUnpatchedSockets\").\n */\n addRequest?: (\n request: http.ClientRequest,\n ...args: Array<unknown>\n ) => void\n }\n}\n\ninterface SocketConnectionEventData {\n socket: net.Socket | tls.TLSSocket\n connectionOptions: NetworkConnectionOptions\n controller: TcpSocketController | TlsSocketController\n}\n\nclass SocketConnectionEvent<\n DataType extends SocketConnectionEventData = SocketConnectionEventData,\n> extends TypedEvent<DataType, void, 'connection'> {\n public socket: net.Socket | tls.TLSSocket\n public connectionOptions: NetworkConnectionOptions\n public controller: TcpSocketController | TlsSocketController\n\n constructor(data: DataType) {\n super(...(['connection', {}] as any))\n\n this.socket = data.socket\n this.connectionOptions = data.connectionOptions\n this.controller = data.controller\n }\n}\n\ntype SocketEventMap = {\n connection: SocketConnectionEvent\n}\n\nconst logger = createLogger('socket')\n\n/**\n * A DNS lookup function for intercepted sockets. It always succeeds,\n * resolving any hostname to the loopback address. This ensures the\n * \"lookup\"/\"connectionAttempt\" socket events fire even for non-existent\n * hosts, and no real DNS resolution is performed. Passthrough\n * connections are created with the original options and use the real\n * (or the caller's custom) lookup instead.\n */\nconst mockLookup: net.LookupFunction = (hostname, dnsOptions, callback) => {\n const family = dnsOptions.family === 6 ? 6 : 4\n const address = family === 6 ? '::1' : '127.0.0.1'\n\n /**\n * @note Call back asynchronously since DNS lookup is always\n * asynchronous in Node.js. Calling back synchronously emits\n * the \"lookup\"/\"connectionAttempt\" socket events before the\n * consumer gets a chance to add listeners for them.\n */\n process.nextTick(() => {\n /**\n * @note Honor the Node.js lookup contract: the callback receives\n * an array of addresses only when the \"all\" option is set\n * (e.g. during the family autoselection). Otherwise, it receives\n * a single address and its family. Node.js rejects an array in\n * the latter case with \"ERR_INVALID_IP_ADDRESS\".\n */\n if (dnsOptions.all) {\n callback(null, [{ address, family }])\n return\n }\n\n callback(null, address, family)\n })\n}\n\n/**\n * Interceptor for `net.Socket` connections.\n */\nexport class SocketInterceptor extends Interceptor<SocketEventMap> {\n static symbol = Symbol.for('socket-interceptor')\n\n protected predicate(): boolean {\n return true\n }\n\n protected setup(): void {\n const interceptor = this\n\n /**\n * @note A synchronous re-entrancy latch for creating passthrough\n * TLS connections. The original \"tls.connect()\" constructs a TLS\n * socket and calls \"socket.connect()\" on it synchronously, and that\n * call must reach Node.js as-is instead of being intercepted again.\n */\n let isCreatingPassthroughConnection = false\n\n this.subscriptions.push(\n /**\n * @note Intercept connections at the \"net.Socket.prototype.connect\"\n * level instead of patching the \"net.connect()\" module function.\n * ESM consumers snapshot the module bindings at import time\n * (\"import * as net from 'node:net'\"), so reassigning \"net.connect\"\n * is invisible to them. Every client connection ends up calling\n * \"Socket.prototype.connect\" (including the one made by the original\n * \"net.connect()\"), and prototype mutations are visible regardless\n * of how the module was imported.\n */\n patchesRegistry.applyPatch(\n net.Socket.prototype,\n 'connect',\n (realSocketConnect) => {\n return function connect(this: net.Socket, ...args: [any, any]) {\n const socket = this\n\n /**\n * @note Skip the sockets this interceptor already controls\n * (the mock connect call below, re-connects of an intercepted\n * socket, passthrough sockets) and the sockets created while\n * dialing a passthrough TLS connection. Their connects must\n * reach Node.js as-is.\n */\n if (socket[kPatched] || isCreatingPassthroughConnection) {\n return realSocketConnect.apply(socket, args)\n }\n\n logger.verbose('socket.connect() %o', args)\n\n /**\n * @note The original \"net.connect()\"/\"tls.connect()\" normalize\n * the arguments themselves and call this method with the\n * normalized array instead of the individual arguments.\n */\n const connectArgs = (\n Array.isArray(args[0]) ? args[0] : args\n ) as typeof args\n\n const [transportConnectionOptions, connectionCallback] =\n normalizeNetConnectArgs(connectArgs)\n\n logger.verbose('connection options %o', {\n transportConnectionOptions,\n connectionCallback,\n })\n\n let controller: TcpSocketController\n let connectionOptions: NetworkConnectionOptions\n\n if (socket instanceof tls.TLSSocket) {\n /**\n * @note TLS sockets arrive here from the original\n * \"tls.connect()\", which connects the transport of the TLS\n * socket it constructs (\"connectionCallback\" is its internal\n * \"_start\" handshake trigger). The original TLS connection\n * options are recovered from the socket instance since the\n * construction has already happened.\n */\n const realTlsConnectionOptions = getTlsConnectOptions(socket)\n const [tlsConnectionOptions] = normalizeTlsConnectArgs([\n {\n ...transportConnectionOptions,\n ...realTlsConnectionOptions,\n } as tls.ConnectionOptions,\n ])\n\n connectionOptions = tlsConnectionOptions\n controller = new TlsSocketController(\n socket,\n () => {\n /**\n * @note Create the passthrough connection via the original\n * \"tls.connect()\" with the original connection options\n * (the real DNS lookup and the caller's certificate\n * validation included). The latch exempts the transport\n * connect of that connection from interception.\n */\n isCreatingPassthroughConnection = true\n\n try {\n return tls.connect(\n (realTlsConnectionOptions ??\n tlsConnectionOptions) as tls.ConnectionOptions\n )\n } finally {\n isCreatingPassthroughConnection = false\n }\n },\n tlsConnectionOptions\n )\n } else {\n /**\n * @note Create passthrough connections without the connection\n * callback. The callback is already registered as a \"connect\"\n * listener on the consumer's socket. Passing it to the\n * passthrough connection would invoke it twice.\n */\n const passthroughArgs = connectArgs.filter((arg) => {\n return typeof arg !== 'function'\n }) as typeof args\n\n /**\n * @note Create the passthrough socket with the original\n * options, the same way \"net.connect()\" does. Connect it via\n * the unpatched method so the passthrough connection is not\n * intercepted again.\n */\n const socketOptions =\n connectArgs[0] !== null &&\n typeof connectArgs[0] === 'object' &&\n !('href' in connectArgs[0])\n ? connectArgs[0]\n : {}\n\n connectionOptions = transportConnectionOptions\n controller = new TcpSocketController(socket, () => {\n const passthroughSocket = new net.Socket(socketOptions)\n Reflect.apply(\n realSocketConnect,\n passthroughSocket,\n passthroughArgs\n )\n return passthroughSocket\n })\n }\n\n process.nextTick(() => {\n if (socket.destroyed) {\n return\n }\n\n /**\n * @note Expect a verdict on this connection from every\n * \"connection\" listener before emitting the event. With no\n * listeners to claim the connection (or once every listener\n * declines it), the controller passes it through as-is.\n */\n controller.awaitVerdicts(\n interceptor.listenerCount('connection')\n )\n\n interceptor.emitter.emit(\n new SocketConnectionEvent({\n socket: controller.serverSocket,\n controller,\n connectionOptions,\n })\n )\n\n logger.verbose('emitted \"connection\" event!')\n })\n\n logger.verbose('connecting the socket...')\n\n /**\n * @note The requested local address/port are stripped from the\n * actual \"socket.connect()\" call by the controller to prevent\n * binding the intercepted socket (see the \"connect\" proxy).\n */\n const mockConnectionOptions = {\n ...transportConnectionOptions,\n }\n\n // Patch the lookup option so DNS lookup always succeeds.\n mockConnectionOptions.lookup = mockLookup\n\n try {\n /**\n * @note The normalized options are looser than the declared\n * \"SocketConnectOpts\" (e.g. the port may be a string when a\n * URL is passed). Node.js validates them at runtime.\n * This call goes through the controller's \"connect\" proxy\n * and lands back in this patch, where the \"kPatched\" check\n * above delegates it to the unpatched method.\n */\n return socket.connect(\n mockConnectionOptions as net.SocketConnectOpts,\n connectionCallback ?? undefined\n )\n } catch (error) {\n /**\n * @note \"socket.connect()\" can throw synchronously on invalid\n * input (e.g. a bad port). Destroy the socket so the pending\n * interception tick does not act on it, then let the error\n * propagate to the consumer like in Node.js.\n */\n socket.destroy()\n throw error\n }\n }\n }\n ),\n this.#stopReusingUnpatchedSockets()\n )\n\n /**\n * @note \"net.connect()\"/\"net.createConnection()\" need no patching of\n * their own: both construct a \"net.Socket\" and call the patched\n * \"Socket.prototype.connect\" on it.\n */\n }\n\n /**\n * Prevent the `net.Socket` instances created before this interceptor\n * was applied from getting reused by an `Agent`. Purging them from the\n * keep-alive pool forces the agent to establish new (intercepted)\n * connections instead.\n */\n #stopReusingUnpatchedSockets(): () => void {\n /**\n * @note \"Agent.prototype.addRequest\" is undocumented but stable:\n * its signature changed once (the keep-alive Agent rewrite in\n * Node.js 0.12), and the ecosystem (agent-base, agentkeepalive,\n * APM wrappers) has relied on it ever since. \"https.Agent\"\n * inherits it, so a single patch covers both.\n */\n if (typeof http.Agent.prototype.addRequest !== 'function') {\n return () => {}\n }\n\n return patchesRegistry.applyPatch(\n http.Agent.prototype,\n 'addRequest',\n (realAddRequest) => {\n return function (this: http.Agent, ...args) {\n /**\n * @note Destroy the free sockets created before the interceptor\n * was applied. Destroying flips their \"destroyed\" state\n * synchronously, so the original \"addRequest\" below discards\n * them and dials a new (intercepted) connection instead.\n * The \"freeSockets\" pool only contains idle sockets by\n * definition, so destroying them aborts nothing in-flight.\n */\n for (const sockets of Object.values(this.freeSockets)) {\n if (sockets == null) {\n continue\n }\n\n for (const socket of sockets) {\n if (!socket[kPatched]) {\n socket.destroy()\n }\n }\n }\n\n return realAddRequest?.apply(this, args)\n }\n }\n )\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"source-CIgPng7r.js","names":["constants","#checkError","#upgrade","#requestBodyStream","#responseBodyStream","#modifyHttpHeaders"],"sources":["../../src/request-context.ts","../../src/interceptors/http/forward-events.ts","../../src/events/http.ts","../../src/interceptors/net/utils/connection-options-to-url.ts","../../src/interceptors/http/http-parser/llhttp/constants.cjs","../../src/interceptors/http/http-parser/index.ts","../../src/interceptors/http/http-parser.ts","../../src/utils/is-node-like-error.ts","../../src/utils/handle-request.ts","../../src/interceptors/http/source.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport type { Logger } from './utils/logger'\n\ninterface RequestContext {\n initiator: unknown\n logger?: Logger\n transformRequest?: (request: Request) => Request\n}\n\nexport const requestContext = new AsyncLocalStorage<RequestContext>()\n\nexport function runInRequestContext<T>(callback: () => T, logger?: Logger): T {\n /**\n * @note Never shadow an existing request context. Nested calls\n * (e.g. a patched entry point re-entered synchronously, or a request\n * made within the fetch/XMLHttpRequest interceptor context) must run\n * within the parent context so the sockets they create capture it.\n */\n if (requestContext.getStore()) {\n return callback()\n }\n\n /**\n * @note The initiator is the callback's return value (e.g. the\n * \"ClientRequest\" instance), so it cannot be known before running\n * the callback. The context is mutated in place once the callback\n * returns; readers hold the context object by reference and sample\n * \"initiator\" only after the request has been written.\n */\n const context: RequestContext = {\n initiator: undefined,\n logger,\n }\n\n return requestContext.run(context, () => {\n const initiator = callback()\n context.initiator = initiator\n return initiator\n })\n}\n","import { type Emitter } from 'rettime'\nimport {\n type HttpRequestEventMap,\n type HttpResponseEvent,\n} from '#/src/events/http'\nimport { type Interceptor } from '#/src/interceptor'\nimport { type DisposableSubscription } from '#/src/disposable'\nimport { createLogger } from '#/src/utils/logger'\n\nconst logger = createLogger('http-request')\n\ninterface ForwardHttpEventsOptions {\n source: Interceptor<HttpRequestEventMap>\n emitter: Emitter<HttpRequestEventMap>\n predicate: (initiator: unknown) => boolean\n responsePredicate?: (event: HttpResponseEvent) => boolean\n}\n\nexport function forwardHttpEvents(\n options: ForwardHttpEventsOptions\n): DisposableSubscription {\n const controller = new AbortController()\n const { source, emitter, predicate, responsePredicate } = options\n\n source.on(\n 'request',\n async (event) => {\n if (predicate(event.initiator)) {\n logger.verbose('forwarding \"request\" event %o', {\n requestId: event.requestId,\n })\n await emitter.emitAsPromise(event)\n }\n },\n {\n signal: controller.signal,\n }\n )\n\n const responseListener: Emitter.Listener<\n Emitter<HttpRequestEventMap>,\n 'response'\n > = async (event) => {\n if (\n predicate(event.initiator) &&\n (responsePredicate == null || responsePredicate(event))\n ) {\n logger.verbose('forwarding \"response\" event %o', {\n requestId: event.requestId,\n responseType: event.responseType,\n })\n await emitter.emitAsPromise(event)\n }\n }\n\n const unhandledExceptionListener: Emitter.Listener<\n Emitter<HttpRequestEventMap>,\n 'unhandledException'\n > = async (event) => {\n if (predicate(event.initiator)) {\n logger.verbose('forwarding \"unhandledException\" event %o', {\n requestId: event.requestId,\n })\n await emitter.emitAsPromise(event)\n }\n }\n\n const addResponseListener = (): void => {\n if (!source.listeners('response').includes(responseListener)) {\n source.on('response', responseListener, {\n signal: controller.signal,\n })\n }\n }\n\n const addUnhandledExceptionListener = (): void => {\n if (\n !source\n .listeners('unhandledException')\n .includes(unhandledExceptionListener)\n ) {\n source.on('unhandledException', unhandledExceptionListener, {\n signal: controller.signal,\n })\n }\n }\n\n if (emitter.listenerCount('response') > 0) {\n addResponseListener()\n }\n\n if (emitter.listenerCount('unhandledException') > 0) {\n addUnhandledExceptionListener()\n }\n\n emitter.hooks.on(\n 'newListener',\n (type) => {\n if (type === 'response') {\n addResponseListener()\n }\n\n if (type === 'unhandledException') {\n addUnhandledExceptionListener()\n }\n },\n {\n signal: controller.signal,\n persist: true,\n }\n )\n\n emitter.hooks.on(\n 'removeListener',\n (type) => {\n if (type === 'response' && emitter.listenerCount('response') === 0) {\n source.removeListener('response', responseListener)\n }\n\n if (\n type === 'unhandledException' &&\n emitter.listenerCount('unhandledException') === 0\n ) {\n source.removeListener(\n 'unhandledException',\n unhandledExceptionListener\n )\n }\n },\n {\n signal: controller.signal,\n persist: true,\n }\n )\n\n return () => {\n controller.abort()\n }\n}\n","import { TypedEvent } from 'rettime'\nimport type { RequestController } from '../request-controller'\n\nexport interface HttpRequestEventData {\n request: Request\n requestId: string\n initiator: unknown\n controller: RequestController\n}\n\nexport class HttpRequestEvent<\n DataType extends HttpRequestEventData = HttpRequestEventData,\n> extends TypedEvent<DataType, void, 'request'> {\n public request: Request\n public requestId: string\n public initiator: unknown\n public controller: RequestController\n\n constructor(data: DataType) {\n super(...(['request', {}] as any))\n\n this.request = data.request\n this.requestId = data.requestId\n this.initiator = data.initiator\n this.controller = data.controller\n }\n}\n\nexport type HttpResponseType = 'mock' | 'original'\n\ninterface HttpResponseEventData {\n response: Response\n responseType: HttpResponseType\n request: Request\n requestId: string\n initiator: unknown\n}\n\nexport class HttpResponseEvent<\n DataType extends HttpResponseEventData = HttpResponseEventData,\n> extends TypedEvent<DataType, void, 'response'> {\n public response: Response\n public responseType: HttpResponseType\n public request: Request\n public requestId: string\n public initiator: unknown\n\n constructor(data: DataType) {\n super(...(['response', {}] as any))\n\n this.response = data.response\n this.responseType = data.responseType\n this.request = data.request\n this.requestId = data.requestId\n this.initiator = data.initiator\n }\n}\n\ninterface UnhandledHttpExceptionEventData {\n error: unknown\n request: Request\n requestId: string\n initiator: unknown\n controller: RequestController\n}\n\nexport class UnhandledHttpException<\n DataType extends UnhandledHttpExceptionEventData =\n UnhandledHttpExceptionEventData,\n> extends TypedEvent<DataType, void, 'unhandledException'> {\n public error: unknown\n public request: Request\n public requestId: string\n public initiator: unknown\n public controller: RequestController\n\n constructor(data: DataType) {\n super(...(['unhandledException', {}] as any))\n\n this.error = data.error\n this.request = data.request\n this.requestId = data.requestId\n this.initiator = data.initiator\n this.controller = data.controller\n }\n}\n\nexport type HttpRequestEventMap = {\n request: HttpRequestEvent\n response: HttpResponseEvent\n unhandledException: UnhandledHttpException\n}\n","import net from 'node:net'\nimport tls from 'node:tls'\nimport { NetworkConnectionOptions } from './normalize-net-connect-args'\n\n/**\n * Creates a `URL` instance out of the `net.connect()` options.\n * @note This implies that the passed connection is an HTTP connection.\n */\nexport function connectionOptionsToUrl(\n options: NetworkConnectionOptions,\n socket: net.Socket\n): URL {\n const isIPv6 = net.isIPv6(options.host || '')\n const protocol =\n socket instanceof tls.TLSSocket\n ? 'https:'\n : getProtocolByConnectionOptions(options)\n const host = options.host || 'localhost'\n\n const url = new URL(`${protocol}//${isIPv6 ? `[${host}]` : host}`)\n\n if (options.path) {\n url.pathname = options.path\n }\n\n if (options.port) {\n url.port = options.port.toString()\n }\n\n if (options.auth) {\n const [username, password] = options.auth.split(':')\n /**\n * Authentication options are provided as plain values.\n * Encode them to form a valid URL.\n * @see https://github.com/nodejs/node/blob/f3adc11e37b8bfaaa026ea85c1cf22e3a0e29ae9/lib/internal/url.js#L1452\n */\n url.username = encodeURIComponent(username)\n url.password = encodeURIComponent(password)\n }\n\n return url\n}\n\nfunction getProtocolByConnectionOptions(\n options: NetworkConnectionOptions\n): 'https:' | 'http:' | (string & {}) {\n if (options.protocol) {\n return options.protocol\n }\n\n if (options.port === 443) {\n return 'https:'\n }\n\n return 'http:'\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.SPECIAL_HEADERS = exports.MINOR = exports.MAJOR = exports.QDTEXT = exports.CONNECTION_TOKEN_CHARS = exports.RELAXED_HEADER_CHARS = exports.HEADER_CHARS = exports.HTAB_SP_VCHAR_OBS_TEXT = exports.SP = exports.HTAB = exports.TOKEN = exports.HEX = exports.URL_CHAR = exports.USERINFO_CHARS = exports.MARK = exports.ALPHANUM = exports.DIGIT = exports.HEX_MAP = exports.NUM_MAP = exports.ALPHA = exports.METHODS = exports.METHODS_HTTP = exports.METHODS_HTTP2 = exports.METHODS_HTTP1 = exports.METHODS_RTSP = exports.METHODS_RAOP = exports.METHODS_AIRPLAY = exports.METHODS_ICECAST = exports.METHODS_NON_STANDARD = exports.METHODS_CALDAV = exports.METHODS_UPNP = exports.METHODS_SUBVERSION = exports.METHODS_WEBDAV = exports.METHODS_BASIC_HTTP = exports.METHODS_HTTP1_HEAD = exports.HEADER_STATE = exports.FINISH = exports.STATUSES = exports.LENIENT_FLAGS = exports.FLAGS = exports.TYPE = exports.ERROR = void 0;\nexports.ERROR = {\n OK: 0,\n INTERNAL: 1,\n STRICT: 2,\n CR_EXPECTED: 25,\n LF_EXPECTED: 3,\n UNEXPECTED_CONTENT_LENGTH: 4,\n UNEXPECTED_SPACE: 30,\n CLOSED_CONNECTION: 5,\n INVALID_METHOD: 6,\n INVALID_URL: 7,\n INVALID_CONSTANT: 8,\n INVALID_VERSION: 9,\n INVALID_HEADER_TOKEN: 10,\n INVALID_CONTENT_LENGTH: 11,\n INVALID_CHUNK_SIZE: 12,\n INVALID_STATUS: 13,\n INVALID_EOF_STATE: 14,\n INVALID_TRANSFER_ENCODING: 15,\n CB_MESSAGE_BEGIN: 16,\n CB_HEADERS_COMPLETE: 17,\n CB_MESSAGE_COMPLETE: 18,\n CB_CHUNK_HEADER: 19,\n CB_CHUNK_COMPLETE: 20,\n PAUSED: 21,\n PAUSED_UPGRADE: 22,\n PAUSED_H2_UPGRADE: 23,\n USER: 24,\n CB_URL_COMPLETE: 26,\n CB_STATUS_COMPLETE: 27,\n CB_METHOD_COMPLETE: 32,\n CB_VERSION_COMPLETE: 33,\n CB_HEADER_FIELD_COMPLETE: 28,\n CB_HEADER_VALUE_COMPLETE: 29,\n CB_CHUNK_EXTENSION_NAME_COMPLETE: 34,\n CB_CHUNK_EXTENSION_VALUE_COMPLETE: 35,\n CB_RESET: 31,\n CB_PROTOCOL_COMPLETE: 38,\n};\nexports.TYPE = {\n BOTH: 0, // default\n REQUEST: 1,\n RESPONSE: 2,\n};\nexports.FLAGS = {\n CONNECTION_KEEP_ALIVE: 1 << 0,\n CONNECTION_CLOSE: 1 << 1,\n CONNECTION_UPGRADE: 1 << 2,\n CHUNKED: 1 << 3,\n UPGRADE: 1 << 4,\n CONTENT_LENGTH: 1 << 5,\n SKIPBODY: 1 << 6,\n TRAILING: 1 << 7,\n // 1 << 8 is unused\n TRANSFER_ENCODING: 1 << 9,\n};\nexports.LENIENT_FLAGS = {\n HEADERS: 1 << 0,\n CHUNKED_LENGTH: 1 << 1,\n KEEP_ALIVE: 1 << 2,\n TRANSFER_ENCODING: 1 << 3,\n VERSION: 1 << 4,\n DATA_AFTER_CLOSE: 1 << 5,\n OPTIONAL_LF_AFTER_CR: 1 << 6,\n OPTIONAL_CRLF_AFTER_CHUNK: 1 << 7,\n OPTIONAL_CR_BEFORE_LF: 1 << 8,\n SPACES_AFTER_CHUNK_SIZE: 1 << 9,\n HEADER_VALUE_RELAXED: 1 << 10,\n};\nexports.STATUSES = {\n CONTINUE: 100,\n SWITCHING_PROTOCOLS: 101,\n PROCESSING: 102,\n EARLY_HINTS: 103,\n RESPONSE_IS_STALE: 110, // Unofficial\n REVALIDATION_FAILED: 111, // Unofficial\n DISCONNECTED_OPERATION: 112, // Unofficial\n HEURISTIC_EXPIRATION: 113, // Unofficial\n MISCELLANEOUS_WARNING: 199, // Unofficial\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NON_AUTHORITATIVE_INFORMATION: 203,\n NO_CONTENT: 204,\n RESET_CONTENT: 205,\n PARTIAL_CONTENT: 206,\n MULTI_STATUS: 207,\n ALREADY_REPORTED: 208,\n TRANSFORMATION_APPLIED: 214, // Unofficial\n IM_USED: 226,\n MISCELLANEOUS_PERSISTENT_WARNING: 299, // Unofficial\n MULTIPLE_CHOICES: 300,\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n SEE_OTHER: 303,\n NOT_MODIFIED: 304,\n USE_PROXY: 305,\n SWITCH_PROXY: 306, // No longer used\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n LENGTH_REQUIRED: 411,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n URI_TOO_LONG: 414,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n EXPECTATION_FAILED: 417,\n IM_A_TEAPOT: 418,\n PAGE_EXPIRED: 419, // Unofficial\n ENHANCE_YOUR_CALM: 420, // Unofficial\n MISDIRECTED_REQUEST: 421,\n UNPROCESSABLE_ENTITY: 422,\n LOCKED: 423,\n FAILED_DEPENDENCY: 424,\n TOO_EARLY: 425,\n UPGRADE_REQUIRED: 426,\n PRECONDITION_REQUIRED: 428,\n TOO_MANY_REQUESTS: 429,\n REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL: 430, // Unofficial\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n LOGIN_TIMEOUT: 440, // Unofficial\n NO_RESPONSE: 444, // Unofficial\n RETRY_WITH: 449, // Unofficial\n BLOCKED_BY_PARENTAL_CONTROL: 450, // Unofficial\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n CLIENT_CLOSED_LOAD_BALANCED_REQUEST: 460, // Unofficial\n INVALID_X_FORWARDED_FOR: 463, // Unofficial\n REQUEST_HEADER_TOO_LARGE: 494, // Unofficial\n SSL_CERTIFICATE_ERROR: 495, // Unofficial\n SSL_CERTIFICATE_REQUIRED: 496, // Unofficial\n HTTP_REQUEST_SENT_TO_HTTPS_PORT: 497, // Unofficial\n INVALID_TOKEN: 498, // Unofficial\n CLIENT_CLOSED_REQUEST: 499, // Unofficial\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n VARIANT_ALSO_NEGOTIATES: 506,\n INSUFFICIENT_STORAGE: 507,\n LOOP_DETECTED: 508,\n BANDWIDTH_LIMIT_EXCEEDED: 509,\n NOT_EXTENDED: 510,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n WEB_SERVER_UNKNOWN_ERROR: 520, // Unofficial\n WEB_SERVER_IS_DOWN: 521, // Unofficial\n CONNECTION_TIMEOUT: 522, // Unofficial\n ORIGIN_IS_UNREACHABLE: 523, // Unofficial\n TIMEOUT_OCCURED: 524, // Unofficial\n SSL_HANDSHAKE_FAILED: 525, // Unofficial\n INVALID_SSL_CERTIFICATE: 526, // Unofficial\n RAILGUN_ERROR: 527, // Unofficial\n SITE_IS_OVERLOADED: 529, // Unofficial\n SITE_IS_FROZEN: 530, // Unofficial\n IDENTITY_PROVIDER_AUTHENTICATION_ERROR: 561, // Unofficial\n NETWORK_READ_TIMEOUT: 598, // Unofficial\n NETWORK_CONNECT_TIMEOUT: 599, // Unofficial\n};\nexports.FINISH = {\n SAFE: 0,\n SAFE_WITH_CB: 1,\n UNSAFE: 2,\n};\nexports.HEADER_STATE = {\n GENERAL: 0,\n CONNECTION: 1,\n CONTENT_LENGTH: 2,\n TRANSFER_ENCODING: 3,\n UPGRADE: 4,\n CONNECTION_KEEP_ALIVE: 5,\n CONNECTION_CLOSE: 6,\n CONNECTION_UPGRADE: 7,\n TRANSFER_ENCODING_CHUNKED: 8,\n};\nexports.METHODS_HTTP1_HEAD = {\n HEAD: 2,\n};\n/**\n * HTTP methods as defined by RFC-9110 and other specifications.\n * @see https://httpwg.org/specs/rfc9110.html#method.definitions\n */\nexports.METHODS_BASIC_HTTP = {\n DELETE: 0,\n GET: 1,\n ...exports.METHODS_HTTP1_HEAD,\n POST: 3,\n PUT: 4,\n CONNECT: 5,\n OPTIONS: 6,\n TRACE: 7,\n /**\n * @see https://www.rfc-editor.org/rfc/rfc5789.html\n */\n PATCH: 28,\n /* RFC-2068, section 19.6.1.2 */\n LINK: 31,\n UNLINK: 32,\n};\nexports.METHODS_WEBDAV = {\n COPY: 8,\n LOCK: 9,\n MKCOL: 10,\n MOVE: 11,\n PROPFIND: 12,\n PROPPATCH: 13,\n SEARCH: 14,\n UNLOCK: 15,\n BIND: 16,\n REBIND: 17,\n UNBIND: 18,\n ACL: 19,\n};\nexports.METHODS_SUBVERSION = {\n REPORT: 20,\n MKACTIVITY: 21,\n CHECKOUT: 22,\n MERGE: 23,\n};\nexports.METHODS_UPNP = {\n 'M-SEARCH': 24,\n NOTIFY: 25,\n SUBSCRIBE: 26,\n UNSUBSCRIBE: 27,\n};\nexports.METHODS_CALDAV = {\n MKCALENDAR: 30,\n};\nexports.METHODS_NON_STANDARD = {\n /**\n * Not defined in any RFC but commonly used\n */\n PURGE: 29,\n /* DRAFT https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-02.html */\n QUERY: 46,\n};\nexports.METHODS_ICECAST = {\n SOURCE: 33,\n};\nexports.METHODS_AIRPLAY = {\n GET: 1,\n POST: 3,\n};\nexports.METHODS_RAOP = {\n FLUSH: 45,\n};\n/* RFC-2326 RTSP */\nexports.METHODS_RTSP = {\n OPTIONS: exports.METHODS_BASIC_HTTP.OPTIONS,\n DESCRIBE: 35,\n ANNOUNCE: 36,\n SETUP: 37,\n PLAY: 38,\n PAUSE: 39,\n TEARDOWN: 40,\n GET_PARAMETER: 41,\n SET_PARAMETER: 42,\n REDIRECT: 43,\n RECORD: 44,\n ...exports.METHODS_AIRPLAY,\n ...exports.METHODS_RAOP,\n};\nexports.METHODS_HTTP1 = {\n ...exports.METHODS_BASIC_HTTP,\n ...exports.METHODS_WEBDAV,\n ...exports.METHODS_SUBVERSION,\n ...exports.METHODS_UPNP,\n ...exports.METHODS_CALDAV,\n ...exports.METHODS_NON_STANDARD,\n // TODO(indutny): should we allow it with HTTP?\n ...exports.METHODS_ICECAST,\n};\nexports.METHODS_HTTP2 = {\n /**\n * RFC-9113, section 11.6\n * @see https://www.rfc-editor.org/rfc/rfc9113.html#preface\n */\n PRI: 34,\n};\nexports.METHODS_HTTP = {\n ...exports.METHODS_HTTP1,\n ...exports.METHODS_HTTP2,\n};\nexports.METHODS = {\n ...exports.METHODS_HTTP1,\n ...exports.METHODS_HTTP2,\n ...exports.METHODS_RTSP,\n};\n// ALPHA: https://tools.ietf.org/html/rfc5234#appendix-B.1\nexports.ALPHA = [\n \"A\", \"a\", \"B\", \"b\", \"C\", \"c\", \"D\", \"d\",\n \"E\", \"e\", \"F\", \"f\", \"G\", \"g\", \"H\", \"h\",\n \"I\", \"i\", \"J\", \"j\", \"K\", \"k\", \"L\", \"l\",\n \"M\", \"m\", \"N\", \"n\", \"O\", \"o\", \"P\", \"p\",\n \"Q\", \"q\", \"R\", \"r\", \"S\", \"s\", \"T\", \"t\",\n \"U\", \"u\", \"V\", \"v\", \"W\", \"w\", \"X\", \"x\",\n \"Y\", \"y\", \"Z\", \"z\",\n];\nexports.NUM_MAP = {\n 0: 0, 1: 1, 2: 2, 3: 3, 4: 4,\n 5: 5, 6: 6, 7: 7, 8: 8, 9: 9,\n};\nexports.HEX_MAP = {\n 0: 0, 1: 1, 2: 2, 3: 3, 4: 4,\n 5: 5, 6: 6, 7: 7, 8: 8, 9: 9,\n A: 0XA, B: 0XB, C: 0XC, D: 0XD, E: 0XE, F: 0XF,\n a: 0xa, b: 0xb, c: 0xc, d: 0xd, e: 0xe, f: 0xf,\n};\n// DIGIT: https://tools.ietf.org/html/rfc5234#appendix-B.1\nexports.DIGIT = [\n '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n];\nexports.ALPHANUM = [...exports.ALPHA, ...exports.DIGIT];\nexports.MARK = ['-', '_', '.', '!', '~', '*', '\\'', '(', ')'];\nexports.USERINFO_CHARS = [...exports.ALPHANUM, ...exports.MARK, '%', ';', ':', '&', '=', '+', '$', ','];\n// TODO(indutny): use RFC\nexports.URL_CHAR = [\n '!', '\"', '$', '%', '&', '\\'',\n '(', ')', '*', '+', ',', '-', '.', '/',\n ':', ';', '<', '=', '>',\n '@', '[', '\\\\', ']', '^', '_',\n '`',\n '{', '|', '}', '~',\n ...exports.ALPHANUM\n];\nexports.HEX = [...exports.DIGIT, 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'];\n/* Tokens as defined by rfc 2616. Also lowercases them.\n * token = 1*<any CHAR except CTLs or separators>\n * separators = \"(\" | \")\" | \"<\" | \">\" | \"@\"\n * | \",\" | \";\" | \":\" | \"\\\" | <\">\n * | \"/\" | \"[\" | \"]\" | \"?\" | \"=\"\n * | \"{\" | \"}\" | SP | HT\n */\nexports.TOKEN = [\n '!', '#', '$', '%', '&', '\\'',\n '*', '+', '-', '.',\n '^', '_', '`',\n '|', '~',\n ...exports.ALPHANUM\n];\n// HTAB: https://tools.ietf.org/html/rfc5234#appendix-B.1\nexports.HTAB = ['\\t'];\n// SP: https://tools.ietf.org/html/rfc5234#appendix-B.1\nexports.SP = [' '];\n// VCHAR: https://tools.ietf.org/html/rfc5234#appendix-B.1\nconst VCHAR = [\n 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\n 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,\n 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,\n 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,\n 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\n 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,\n 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,\n 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,\n 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,\n 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,\n 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,\n 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,\n];\n// OBS_TEXT: https://datatracker.ietf.org/doc/html/rfc9110#name-collected-abnf\n// 0x80 - 0xff\nconst OBS_TEXT = [\n 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,\n 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,\n 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\n 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,\n 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\n 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,\n 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\n 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,\n 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\n 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,\n 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\n 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,\n 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,\n];\nexports.HTAB_SP_VCHAR_OBS_TEXT = [...exports.HTAB, ...exports.SP, ...VCHAR, ...OBS_TEXT];\nexports.HEADER_CHARS = exports.HTAB_SP_VCHAR_OBS_TEXT;\nconst RELAXED_CTRL_CHARS = [\n 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Before TAB\n 0x0b, 0x0c, // VT, FF (between TAB and CR)\n 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, // After CR/LF, before space\n 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,\n 0x1e, 0x1f,\n 0x7f, // DEL\n];\n// Relaxed header chars includes control characters (above) that are not allowed\n// by default. This excludes only NULL (0x00), CR (0x0d), LF (0x0a).\nexports.RELAXED_HEADER_CHARS = [...RELAXED_CTRL_CHARS, ...exports.HEADER_CHARS];\n// ',' = \\x2c\nexports.CONNECTION_TOKEN_CHARS = [\n ...exports.HTAB, ...exports.SP,\n 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\n 0x29, 0x2a, 0x2b, /* */ 0x2d, 0x2e, 0x2f, 0x30,\n 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,\n 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,\n 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\n 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,\n 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,\n 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,\n 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,\n 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,\n 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,\n 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,\n ...OBS_TEXT\n];\n// QDTEXT: https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.4\nexports.QDTEXT = [\n ...exports.HTAB, ...exports.SP,\n 0x21,\n 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,\n 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,\n 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,\n 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42,\n 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,\n 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,\n 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,\n 0x5b,\n 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64,\n 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,\n 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,\n 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,\n 0x7d, 0x7e,\n ...OBS_TEXT\n];\nexports.MAJOR = exports.NUM_MAP;\nexports.MINOR = exports.MAJOR;\nexports.SPECIAL_HEADERS = {\n 'connection': exports.HEADER_STATE.CONNECTION,\n 'content-length': exports.HEADER_STATE.CONTENT_LENGTH,\n 'proxy-connection': exports.HEADER_STATE.CONNECTION,\n 'transfer-encoding': exports.HEADER_STATE.TRANSFER_ENCODING,\n 'upgrade': exports.HEADER_STATE.UPGRADE,\n};\nexports.default = {\n ERROR: exports.ERROR,\n TYPE: exports.TYPE,\n FLAGS: exports.FLAGS,\n LENIENT_FLAGS: exports.LENIENT_FLAGS,\n STATUSES: exports.STATUSES,\n FINISH: exports.FINISH,\n HEADER_STATE: exports.HEADER_STATE,\n ALPHA: exports.ALPHA,\n NUM_MAP: exports.NUM_MAP,\n HEX_MAP: exports.HEX_MAP,\n DIGIT: exports.DIGIT,\n ALPHANUM: exports.ALPHANUM,\n MARK: exports.MARK,\n USERINFO_CHARS: exports.USERINFO_CHARS,\n URL_CHAR: exports.URL_CHAR,\n HEX: exports.HEX,\n TOKEN: exports.TOKEN,\n HEADER_CHARS: exports.HEADER_CHARS,\n RELAXED_HEADER_CHARS: exports.RELAXED_HEADER_CHARS,\n CONNECTION_TOKEN_CHARS: exports.CONNECTION_TOKEN_CHARS,\n QDTEXT: exports.QDTEXT,\n HTAB_SP_VCHAR_OBS_TEXT: exports.HTAB_SP_VCHAR_OBS_TEXT,\n MAJOR: exports.MAJOR,\n MINOR: exports.MINOR,\n SPECIAL_HEADERS: exports.SPECIAL_HEADERS,\n METHODS: exports.METHODS,\n METHODS_HTTP: exports.METHODS_HTTP,\n METHODS_HTTP1_HEAD: exports.METHODS_HTTP1_HEAD,\n METHODS_HTTP1: exports.METHODS_HTTP1,\n METHODS_HTTP2: exports.METHODS_HTTP2,\n METHODS_ICECAST: exports.METHODS_ICECAST,\n METHODS_RTSP: exports.METHODS_RTSP,\n};","import fs from 'node:fs'\nimport * as constants from './llhttp/constants.cjs'\n\nexport { constants }\n\nexport interface RequestHeadersComplete {\n versionMajor: number\n versionMinor: number\n rawHeaders: Array<string>\n method: string\n url: string\n upgrade: boolean\n shouldKeepAlive: boolean\n}\n\nexport interface ResponseHeadersComplete {\n versionMajor: number\n versionMinor: number\n rawHeaders: Array<string>\n statusCode: number\n statusMessage: string\n upgrade: boolean\n shouldKeepAlive: boolean\n}\n\nconst KIND_REQUEST = constants.TYPE.REQUEST\nconst KIND_RESPONSE = constants.TYPE.RESPONSE\n\ntype ParserKind = typeof KIND_REQUEST | typeof KIND_RESPONSE\n\nexport interface ParserCallbacks<K extends ParserKind> {\n onMessageBegin?: () => number | void\n onHeadersComplete?: (\n info: K extends typeof KIND_REQUEST\n ? RequestHeadersComplete\n : ResponseHeadersComplete\n ) => number | void\n onBody?: (body: Buffer) => number | void\n onMessageComplete?: () => number | void\n}\n\nexport type RequestParserCallbacks = ParserCallbacks<typeof KIND_REQUEST>\nexport type ResponseParserCallbacks = ParserCallbacks<typeof KIND_RESPONSE>\n\nconst kPointer = Symbol('kPtr')\nconst kUrl = Symbol('kUrl')\nconst kStatusMessage = Symbol('kStatusMessage')\nconst kHeadersFields = Symbol('kHeadersFields')\nconst kHeadersValues = Symbol('kHeadersValues')\nconst kLastHeaderCallback = Symbol('kLastHeaderCallback')\nconst kCallbacks = Symbol('kCallbacks')\nconst kType = Symbol('kType')\n\nconst HEADER_CB_NONE = 0\nconst HEADER_CB_FIELD = 1\nconst HEADER_CB_VALUE = 2\n\nconst parsersMap = new Map<number, HttpParser<any>>()\n\nconst methodNames = Object.fromEntries(\n Object.entries(constants.METHODS).map(([name, num]) => [num, name])\n) as Record<number, string>\n\nfunction readStringFrom(pointer: number, length: number): string {\n return Buffer.from(llhttp_memory.buffer, pointer, length).toString('latin1')\n}\n\n/**\n * @note Reference the base URL through a variable. Bundlers (e.g. Vite)\n * statically rewrite the `new URL('...', import.meta.url)` pattern into\n * an asset URL resolved against the served origin, which breaks reading\n * the WASM binary from the file system in DOM-like test environments.\n */\nconst wasmBaseUrl = import.meta.url\n\nconst llhttpModule = new WebAssembly.Module(\n fs.readFileSync(new URL('./llhttp/llhttp.wasm', wasmBaseUrl))\n)\n\nconst llhttpInstance = new WebAssembly.Instance(llhttpModule, {\n env: {\n wasm_on_message_begin(parserPointer: number) {\n const parser = parsersMap.get(parserPointer)!\n parser[kUrl] = ''\n parser[kStatusMessage] = ''\n parser[kHeadersFields] = []\n parser[kHeadersValues] = []\n parser[kLastHeaderCallback] = HEADER_CB_NONE\n return parser[kCallbacks].onMessageBegin?.() ?? 0\n },\n // Request only\n wasm_on_url(parserPointer: number, at: number, length: number) {\n parsersMap.get(parserPointer)![kUrl] = readStringFrom(at, length)\n return 0\n },\n // Response only\n wasm_on_status(parserPointer: number, at: number, length: number) {\n parsersMap.get(parserPointer)![kStatusMessage] = readStringFrom(\n at,\n length\n )\n return 0\n },\n wasm_on_header_field(parserPointer: number, at: number, length: number) {\n const parser = parsersMap.get(parserPointer)!\n const chunk = readStringFrom(at, length)\n const fields = parser[kHeadersFields]\n\n // llhttp emits header field/value across multiple callbacks when the\n // bytes span buffer boundaries. Concatenate consecutive same-type\n // callbacks into a single entry; switch entries on field<->value transitions.\n if (parser[kLastHeaderCallback] === HEADER_CB_FIELD) {\n fields[fields.length - 1] += chunk\n } else {\n fields.push(chunk)\n parser[kLastHeaderCallback] = HEADER_CB_FIELD\n }\n return 0\n },\n wasm_on_header_value(parserPointer: number, at: number, length: number) {\n const parser = parsersMap.get(parserPointer)!\n const chunk = readStringFrom(at, length)\n const values = parser[kHeadersValues]\n\n if (parser[kLastHeaderCallback] === HEADER_CB_VALUE) {\n values[values.length - 1] += chunk\n } else {\n values.push(chunk)\n parser[kLastHeaderCallback] = HEADER_CB_VALUE\n }\n return 0\n },\n wasm_on_headers_complete(\n parserPointer: number,\n statusCode: number,\n rawUpgrade: number,\n rawShouldKeepAlive: number\n ) {\n const parser = parsersMap.get(parserPointer)!\n const versionMajor = llhttp_get_version_major(parserPointer)\n const versionMinor = llhttp_get_version_minor(parserPointer)\n const rawHeaders: Array<string> = []\n const upgrade = rawUpgrade === 1\n const shouldKeepAlive = rawShouldKeepAlive === 1\n\n for (let c = 0; c < parser[kHeadersFields].length; c++) {\n rawHeaders.push(parser[kHeadersFields][c]!, parser[kHeadersValues][c]!)\n }\n\n if (parser[kType] === KIND_REQUEST) {\n const method = methodNames[llhttp_get_method(parserPointer)]\n const url = parser[kUrl]\n const callback = parser[kCallbacks] as ParserCallbacks<\n typeof KIND_REQUEST\n >\n\n return (\n callback.onHeadersComplete?.({\n versionMajor,\n versionMinor,\n rawHeaders,\n method,\n url,\n upgrade,\n shouldKeepAlive,\n }) ?? 0\n )\n } else {\n const statusCode = llhttp_get_status_code(parserPointer) as number\n const statusMessage = parser[kStatusMessage]\n const callback = parser[kCallbacks] as ParserCallbacks<\n typeof KIND_RESPONSE\n >\n\n return (\n callback.onHeadersComplete?.({\n versionMajor,\n versionMinor,\n rawHeaders,\n statusCode,\n statusMessage,\n upgrade,\n shouldKeepAlive,\n }) ?? 0\n )\n }\n },\n wasm_on_body(parserPointer: number, at: number, length: number) {\n const parser = parsersMap.get(parserPointer)!\n // Create a copy of the body chunk, as the underlying memory buffer is reused by llhttp and can be overwritten on the next callback call.\n // Maybe not the most efficient way, but it is simple and safe.\n const body = Buffer.from(new Uint8Array(llhttp_memory.buffer, at, length))\n return parser[kCallbacks].onBody?.(body) ?? 0\n },\n wasm_on_message_complete(parserPointer: number) {\n return (\n parsersMap.get(parserPointer)![kCallbacks].onMessageComplete?.() ?? 0\n )\n },\n },\n})\n\nconst llhttp_memory = llhttpInstance.exports.memory as WebAssembly.Memory\nconst llhttp_alloc = llhttpInstance.exports.llhttp_alloc as CallableFunction\nconst llhttp_malloc = llhttpInstance.exports.malloc as CallableFunction\nconst llhttp_execute = llhttpInstance.exports.llhttp_execute as CallableFunction\nconst llhttp_get_type = llhttpInstance.exports\n .llhttp_get_type as CallableFunction\nconst llhttp_get_upgrade = llhttpInstance.exports\n .llhttp_get_upgrade as CallableFunction\nconst llhttp_should_keep_alive = llhttpInstance.exports\n .llhttp_should_keep_alive as CallableFunction\nconst llhttp_get_method = llhttpInstance.exports\n .llhttp_get_method as CallableFunction\nconst llhttp_get_status_code = llhttpInstance.exports\n .llhttp_get_status_code as CallableFunction\nconst llhttp_get_version_minor = llhttpInstance.exports\n .llhttp_get_http_minor as CallableFunction\nconst llhttp_get_version_major = llhttpInstance.exports\n .llhttp_get_http_major as CallableFunction\nconst llhttp_get_error_reason = llhttpInstance.exports\n .llhttp_get_error_reason as CallableFunction\nconst llhttp_get_error_pos = llhttpInstance.exports\n .llhttp_get_error_pos as CallableFunction\nconst llhttp_free = llhttpInstance.exports.free as CallableFunction\n\nconst initialize = llhttpInstance.exports._initialize as CallableFunction\ninitialize() // wasi reactor\n\nexport class HttpParser<K extends ParserKind> {\n [kPointer]: number;\n [kUrl]: string = '';\n [kStatusMessage]: string = '';\n [kHeadersFields]: Array<string> = [];\n [kHeadersValues]: Array<string> = [];\n [kLastHeaderCallback]: number = HEADER_CB_NONE;\n [kCallbacks]: ParserCallbacks<K>;\n [kType]: ParserKind\n\n constructor(type: K, callbacks: ParserCallbacks<K>) {\n this[kType] = type\n this[kCallbacks] = callbacks\n\n const parserPointer = llhttp_alloc(type)\n\n if (parserPointer === 0) {\n throw new Error('Failed to allocate llhttp parser')\n }\n\n this[kPointer] = parserPointer\n parsersMap.set(this[kPointer], this)\n }\n\n destroy() {\n // Guard against multiple calls to free/destroy.\n if (this[kPointer] === 0) {\n return\n }\n\n parsersMap.delete(this[kPointer])\n llhttp_free(this[kPointer])\n this[kPointer] = 0\n }\n\n execute(data: Buffer) {\n const pointer = llhttp_malloc(data.byteLength)\n\n if (pointer === 0) {\n throw new Error('Failed to allocate llhttp input buffer')\n }\n\n let ret: number\n try {\n const buffer = new Uint8Array(llhttp_memory.buffer)\n buffer.set(data, pointer)\n ret = llhttp_execute(this[kPointer], pointer, data.byteLength)\n } catch (error) {\n // Free the input buffer if a user callback threw synchronously,\n // otherwise the wasm heap leaks the chunk on every execute() call.\n llhttp_free(pointer)\n throw error\n }\n\n if (ret === constants.ERROR.PAUSED_UPGRADE) {\n // Find how many bytes llhttp consumed\n const errorPos = llhttp_get_error_pos(this[kPointer])\n const consumed = errorPos - pointer\n llhttp_free(pointer)\n // Return the unconsumed trailing bytes (tunnel/protocol data)\n return data.subarray(consumed)\n }\n\n llhttp_free(pointer)\n this.#checkError(ret)\n\n return null // fully consumed\n }\n\n #checkError(errorCode: number) {\n if (errorCode === constants.ERROR.OK) {\n return\n }\n\n const errorPointer = llhttp_get_error_reason(this[kPointer])\n const buffer = new Uint8Array(llhttp_memory.buffer)\n const length = buffer.indexOf(0, errorPointer) - errorPointer\n\n throw new Error(readStringFrom(errorPointer, length))\n }\n}\n","import { Readable } from 'node:stream'\nimport { invariant } from 'outvariant'\nimport { FetchRequest, FetchResponse } from '../../utils/fetch-utils'\nimport { HttpParser } from './http-parser/index'\n\ninterface HttpRequestParserOptions {\n connectionOptions: {\n method?: string\n url: URL\n }\n onRequest: (request: Request, abortController: AbortController) => void\n onMessageComplete?: () => void\n}\n\nexport class HttpRequestParser extends HttpParser<1> {\n #requestBodyStream?: Readable\n #upgrade = false\n\n constructor(options: HttpRequestParserOptions) {\n super(1, {\n onHeadersComplete: ({ rawHeaders, method, url: path, upgrade }) => {\n this.#upgrade = upgrade\n /**\n * @note When the socket is reused, \"connectionOptions\" will point\n * to the \"net.connect()\" call options that established the connection,\n * which may differ from the description of the current request (e.g. method).\n * Rely on the HTTPParser supplying us with the correct \"rawMethod\" number.\n */\n const finalMethod = (\n method ||\n options.connectionOptions.method ||\n 'GET'\n ).toUpperCase()\n\n const url = new URL(path || '', options.connectionOptions.url)\n const headers = FetchResponse.parseRawHeaders([...rawHeaders])\n\n // Translate the basic authorization to request headers.\n // Constructing a Request instance with a URL containing auth is no-op.\n if (url.username || url.password) {\n if (!headers.has('authorization')) {\n const credentials = Buffer.from(\n `${url.username}:${url.password}`\n ).toString('base64')\n headers.set('authorization', `Basic ${credentials}`)\n }\n url.username = ''\n url.password = ''\n }\n\n this.#requestBodyStream = new Readable({\n /**\n * @note Provide the `read()` method so a `Readable` could be\n * used as the actual request body (the stream calls \"read()\").\n */\n read: () => {},\n })\n\n /**\n * @note Expose an abort controller for the parsed request so the\n * consumer can abort it (e.g. when the client destroys the\n * connection before the request is handled).\n */\n const abortController = new AbortController()\n\n const request = new FetchRequest(url, {\n method: finalMethod,\n headers,\n credentials: 'same-origin',\n body: Readable.toWeb(this.#requestBodyStream) as any,\n signal: abortController.signal,\n })\n options.onRequest(request, abortController)\n },\n onBody: (chunk) => {\n invariant(\n this.#requestBodyStream,\n 'Failed to write to a request stream: stream does not exist. This is likely an issue with the library. Please report it on GitHub.'\n )\n\n this.#requestBodyStream.push(chunk)\n },\n onMessageComplete: () => {\n this.#requestBodyStream?.push(null)\n\n /**\n * @note An upgraded exchange (e.g. \"CONNECT\", WebSocket) has\n * no message boundary: it takes the connection over, and the\n * bytes that follow belong to it, not to a next exchange.\n */\n if (!this.#upgrade) {\n options.onMessageComplete?.()\n }\n },\n })\n }\n\n public free(): void {\n this.destroy()\n this.#requestBodyStream?.destroy()\n this.#requestBodyStream = undefined\n }\n}\n\nexport class HttpResponseParser extends HttpParser<2> {\n #responseBodyStream?: Readable | null\n\n constructor(options: { onResponse: (response: Response) => void }) {\n super(2, {\n onHeadersComplete: ({\n rawHeaders,\n statusCode: status,\n statusMessage: statusText,\n }) => {\n const headers = FetchResponse.parseRawHeaders([...rawHeaders])\n\n const response = new FetchResponse(\n FetchResponse.isResponseWithBody(status)\n ? (Readable.toWeb(\n (this.#responseBodyStream = new Readable({ read() {} }))\n ) as any)\n : null,\n {\n status,\n statusText,\n headers,\n }\n )\n\n options.onResponse(response)\n },\n onBody: (chunk) => {\n invariant(\n this.#responseBodyStream,\n 'Failed to read from a response stream: stream does not exist. This is likely an issue with the library. Please report it on GitHub.'\n )\n\n this.#responseBodyStream.push(chunk)\n },\n onMessageComplete: () => {\n this.#responseBodyStream?.push(null)\n },\n })\n }\n\n public free(): void {\n this.destroy()\n this.#responseBodyStream = null\n }\n}\n","export function isNodeLikeError(\n error: unknown\n): error is NodeJS.ErrnoException {\n if (error == null) {\n return false\n }\n\n if (!(error instanceof Error)) {\n return false\n }\n\n return 'code' in error && 'errno' in error\n}\n","import type { Emitter } from 'rettime'\nimport { until } from '@open-draft/until'\nimport {\n HttpRequestEvent,\n HttpRequestEventData,\n UnhandledHttpException,\n type HttpRequestEventMap,\n} from '../events/http'\nimport { RequestController } from '../request-controller'\nimport {\n createServerErrorResponse,\n isResponseError,\n isResponseLike,\n} from './response-utils'\nimport { InterceptorError } from '../interceptor-error'\nimport { isNodeLikeError } from './is-node-like-error'\nimport { isObject } from './is-object'\nimport { formatRequest, type Logger } from './logger'\n\nexport interface HandleRequestOptions {\n initiator: unknown\n requestId: string\n request: Request\n emitter: Emitter<HttpRequestEventMap>\n controller: RequestController\n logger?: Logger\n}\n\nexport async function handleRequest(\n options: HandleRequestOptions\n): Promise<void> {\n if (options.logger?.isEnabled('default')) {\n void formatRequest(options.request).then((message) => {\n options.logger?.info('[%s] %s', options.requestId, message)\n })\n }\n\n const handleResponse = async (\n response: Response | Error | Record<string, any>\n ) => {\n if (response instanceof Error) {\n await options.controller.errorWith(response)\n return true\n }\n\n // Handle \"Response.error()\" instances.\n if (isResponseError(response)) {\n await options.controller.respondWith(response)\n return true\n }\n\n /**\n * Handle normal responses or response-like objects.\n * @note This must come before the arbitrary object check\n * since Response instances are, in fact, objects.\n */\n if (isResponseLike(response)) {\n await options.controller.respondWith(response)\n return true\n }\n\n // Handle arbitrary objects provided to `.errorWith(reason)`.\n if (isObject(response)) {\n await options.controller.errorWith(response)\n return true\n }\n\n return false\n }\n\n const handleResponseError = async (error: unknown): Promise<boolean> => {\n // Forward the special interceptor error instances\n // to the developer. These must not be handled in any way.\n if (error instanceof InterceptorError) {\n throw resultError\n }\n\n // Support mocking Node.js-like errors.\n if (isNodeLikeError(error)) {\n await options.controller.errorWith(error)\n return true\n }\n\n // Handle thrown responses.\n if (error instanceof Response) {\n return await handleResponse(error)\n }\n\n return false\n }\n\n const requestAbortPromise = Promise.withResolvers<void>()\n let requestAbortReason: unknown\n let isRequestAborted = false\n const onAbort = () => {\n isRequestAborted = true\n requestAbortReason = options.request.signal?.reason\n requestAbortPromise.reject(requestAbortReason)\n }\n\n /**\n * @note `signal` is not always defined in React Native.\n */\n if (options.request.signal) {\n if (options.request.signal.aborted) {\n await options.controller.errorWith(options.request.signal.reason)\n return\n }\n\n options.request.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n const [resultError] = await until(async () => {\n // Emit the \"request\" event and wait until all the listeners\n // for that event are finished (e.g. async listeners awaited).\n // By the end of this promise, the developer cannot affect the\n // request anymore.\n const requestEventData: HttpRequestEventData = {\n initiator: options.initiator,\n requestId: options.requestId,\n request: options.request,\n controller: options.controller,\n }\n const requestEvent = new HttpRequestEvent(requestEventData)\n const requestListenersPromise = options.emitter.emitAsPromise(requestEvent)\n\n await Promise.race([\n // Short-circuit the request handling promise if the request gets aborted.\n requestAbortPromise.promise,\n requestListenersPromise,\n options.controller.handled,\n ])\n\n /**\n * @note If the \"request\" listener has replaced the request instance,\n * propagate that mutation back to the underlying insterceptor.\n * This happens with XMLHttpRequest that replaces request instances\n * to correctly reflect the \"withCredentials\" option on the Fetch API request.\n */\n if (requestEvent.request !== options.request) {\n options.request = requestEvent.request\n }\n })\n\n options.request.signal?.removeEventListener('abort', onAbort)\n\n // Handle the request being aborted while waiting for the request listeners.\n if (isRequestAborted) {\n await options.controller.errorWith(requestAbortReason)\n return\n }\n\n if (resultError) {\n // Handle the error during the request listener execution.\n // These can be thrown responses or request errors.\n if (await handleResponseError(resultError)) {\n return\n }\n\n // If the developer has added \"unhandledException\" listeners,\n // allow them to handle the error. They can translate it to a\n // mocked response, network error, or forward it as-is.\n if (options.emitter.listenerCount('unhandledException') > 0) {\n // Create a new request controller just for the unhandled exception case.\n // This is needed because the original controller might have been already\n // interacted with (e.g. \"respondWith\" or \"errorWith\" called on it).\n const unhandledExceptionController = new RequestController(\n options.request,\n {\n /**\n * @note Intentionally empty passthrough handle.\n * This controller is created within another controller and we only need\n * to know if `unhandledException` listeners handled the request.\n */\n passthrough() {},\n async respondWith(response) {\n await handleResponse(response)\n },\n async errorWith(reason) {\n /**\n * @note Handle the result of the unhandled controller\n * in the same way as the original request controller.\n * The exception here is that thrown errors within the\n * \"unhandledException\" event do NOT result in another\n * emit of the same event. They are forwarded as-is.\n */\n await options.controller.errorWith(reason)\n },\n }\n )\n\n await options.emitter.emitAsPromise(\n new UnhandledHttpException({\n initiator: options.initiator,\n error: resultError,\n request: options.request,\n requestId: options.requestId,\n controller: unhandledExceptionController,\n })\n )\n\n // If all the \"unhandledException\" listeners have finished\n // but have not handled the request in any way, passthrough.\n if (\n unhandledExceptionController.readyState !== RequestController.PENDING\n ) {\n return\n }\n }\n\n // Otherwise, coerce unhandled exceptions to a 500 Internal Server Error response.\n await options.controller.respondWith(\n createServerErrorResponse(resultError)\n )\n return\n }\n\n // If the request hasn't been handled by this point, passthrough.\n if (options.controller.readyState === RequestController.PENDING) {\n return await options.controller.passthrough()\n }\n\n return options.controller.handled\n}\n","import net from 'node:net'\nimport {\n METHODS,\n STATUS_CODES,\n ServerResponse,\n IncomingMessage,\n} from 'node:http'\nimport { invariant } from 'outvariant'\nimport { HttpResponseEvent, type HttpRequestEventMap } from '../../events/http'\nimport { RequestController } from '../../request-controller'\nimport {\n getRawFetchHeaders,\n recordRawFetchHeaders,\n} from '../ClientRequest/utils/record-raw-headers'\nimport { SocketInterceptor } from '../net'\nimport { connectionOptionsToUrl } from '../net/utils/connection-options-to-url'\nimport { toBuffer } from '../../utils/buffer-utils'\nimport { createRequestId } from '../../create-request-id'\nimport { HttpRequestParser, HttpResponseParser } from './http-parser'\nimport { handleRequest, HandleRequestOptions } from '../../utils/handle-request'\nimport { isResponseError, kErrorResponse } from '../../utils/response-utils'\nimport { createLogger } from '../../utils/logger'\nimport {\n kRawSocket,\n SocketController,\n type FlushPendingDataFunction,\n} from '../net/socket-controller'\nimport { unwrapPendingData } from '../net/utils/flush-writes'\nimport { FetchResponse } from '../../utils/fetch-utils'\nimport { requestContext } from '../../request-context'\nimport { Interceptor } from '#/src/interceptor'\n\nconst httpLogger = createLogger('http-request')\n\n/**\n * Interceptor for HTTP requests in Node.js.\n * Routes socket connections through an HTTP parser.\n */\nexport class NodeHttpRequestSource extends Interceptor<HttpRequestEventMap> {\n static symbol = Symbol.for('node-http-request-source')\n\n protected predicate(): boolean {\n return true\n }\n\n protected setup(): void {\n const socketInterceptor = Interceptor.singleton(SocketInterceptor)\n socketInterceptor.apply(this)\n this.subscriptions.push(() => {\n socketInterceptor.dispose(this)\n })\n\n /**\n * @note Record the raw values provided to Headers set/append\n * in order to support \"IncomingMessage.prototype.rawHeaders\".\n * This is meant for the headers in mocked responses.\n */\n this.subscriptions.push(recordRawFetchHeaders())\n\n const controller = new AbortController()\n this.subscriptions.push(() => controller.abort())\n\n socketInterceptor.on(\n 'connection',\n ({ connectionOptions, socket, controller: socketController }) => {\n let isHttpConnection: boolean | undefined\n let requestParser: HttpRequestParser | undefined\n let tunnelUrl: URL | undefined\n let abortPendingRequest: (() => void) | undefined\n\n /**\n * @note Capture the request context of the connection itself.\n * The socket is created synchronously within the request async\n * context (e.g. inside the patched `http.request()`), but the\n * first data may reach the socket from a foreign context (e.g.\n * a form-data stream piped into the request), where sampling\n * the request context yields nothing.\n */\n const connectionRequestContext = requestContext.getStore()\n\n /**\n * @note The client destroys the socket synchronously (e.g. Undici\n * on request abort) but the socket teardown events (\"error\",\n * \"close\") are emitted asynchronously, after the consumer has\n * already observed the rejected request promise. Hook into the\n * destroy itself so the pending request is aborted before any\n * of its listeners can resume.\n */\n const rawSocket = socketController[kRawSocket]\n const realSocketDestroy = rawSocket._destroy.bind(rawSocket)\n rawSocket._destroy = (error, callback) => {\n abortPendingRequest?.()\n realSocketDestroy(error, callback)\n }\n\n /**\n * @note Only inspect the first sent packet to determine the protocol.\n * A single socket cannot be used for different protocols.\n */\n socket.on('data', (chunk) => {\n if (isHttpConnection === false) {\n return\n }\n\n /**\n * @note A mocked \"CONNECT\" request has established a tunnel.\n * The data that follows belongs to a new exchange addressed to\n * the tunnel target. The parser stopped at the tunnel boundary\n * (HTTP upgrade semantics), so tear it down and detect the\n * tunneled protocol anew, like on a fresh connection.\n */\n if (tunnelUrl && requestParser) {\n requestParser.free()\n requestParser = undefined\n isHttpConnection = undefined\n\n /**\n * @note Retarget the connection to the tunnel authority.\n * The exchanges that follow belong to the tunnel target,\n * so an unclaimed exchange (HTTP or not) must pass through\n * to that target — not to the proxy, which never actually\n * established this tunnel — like a real established tunnel\n * relays its traffic.\n */\n socketController.reset({\n host: tunnelUrl.hostname,\n port: Number(tunnelUrl.port) || 80,\n path: null,\n })\n }\n\n if (requestParser) {\n requestParser.execute(toBuffer(chunk))\n return\n }\n\n const httpMessage = chunk.toString()\n const httpMethod = httpMessage.split(' ')[0] || ''\n\n // Decline non-HTTP connections so the socket controller can\n // pass them through once every subscriber has declined.\n if (!METHODS.includes(httpMethod.toUpperCase())) {\n isHttpConnection = false\n socketController.decline()\n return\n }\n\n isHttpConnection = true\n\n const baseUrl =\n tunnelUrl ?? connectionOptionsToUrl(connectionOptions, socket)\n\n httpLogger.verbose('handling http message %o', {\n httpMessage,\n httpMethod,\n baseUrl,\n })\n\n // Get the request initiator from the async context, falling\n // back to the context captured at the connection time, then\n // to the underlying socket.\n const requestContextValue =\n requestContext.getStore() ?? connectionRequestContext\n const initiator = requestContextValue?.initiator || socket\n\n requestParser = new HttpRequestParser({\n connectionOptions: {\n method: httpMethod,\n url: baseUrl,\n },\n /**\n * @note The message boundary ends the current exchange.\n * Schedule the controller reset so the next write on this\n * (kept-alive) socket opens a new exchange and buffers for\n * its own verdict instead of following the settled one\n * (e.g. leaking a mocked request to the server of a\n * previously passed-through exchange).\n */\n onMessageComplete: () => {\n socketController.scheduleReset()\n },\n onRequest: async (parsedRequest, requestAbortController) => {\n const request =\n requestContextValue?.transformRequest?.(parsedRequest) ??\n parsedRequest\n\n /**\n * @note A subsequent request arriving on a kept-alive socket\n * that has already been handled (passed through or mocked).\n * Clients like Undici reuse sockets without emitting the\n * \"free\" event, so reset the controller here, at the HTTP\n * message boundary, to handle the new request from the\n * pending state again.\n */\n if (socketController['readyState'] !== SocketController.PENDING) {\n socketController.reset()\n }\n\n const requestId = createRequestId()\n const requestLogger = requestContextValue?.logger ?? httpLogger\n\n httpLogger.verbose('received a parsed HTTP request %o', {\n method: request.method,\n url: request.url,\n })\n\n const requestController = new RequestController(\n request,\n {\n respondWith: async (rawResponse) => {\n httpLogger.verbose('respondWith() %o', {\n status: rawResponse.status,\n statusText: rawResponse.statusText,\n hasBody: rawResponse.body != null,\n })\n\n /**\n * @note The client may destroy the socket (e.g. on request\n * abort) moments before a response arrives. A destroyed\n * socket cannot be claimed and has no one reading it.\n */\n if (socket.destroyed) {\n return\n }\n\n socketController.claim()\n\n const response = FetchResponse.from(rawResponse, {\n url: request.url,\n })\n\n /**\n * @note A successful mocked response to a \"CONNECT\"\n * request establishes a tunnel to the requested authority\n * (e.g. \"127.0.0.1:80\"). The exchange that follows on this\n * socket is addressed to that authority, not to the proxy.\n */\n if (request.method === 'CONNECT' && response.ok) {\n tunnelUrl = new URL(`http://${request.url}`)\n }\n\n /**\n * @note Clone the response before \"respondWith\" because it will\n * consume its body. This way, we can have a readable response copy\n * for the \"response\" event below.\n */\n const responseClone = isResponseError(response)\n ? null\n : response.clone()\n\n const respond = () => {\n return this.respondWith({\n socket: socketController[kRawSocket],\n request: context.request,\n response,\n })\n }\n\n if (responseClone) {\n await this.emitter.emitAsPromise(\n new HttpResponseEvent({\n initiator,\n requestId,\n request: context.request,\n response: responseClone,\n responseType: 'mock',\n })\n )\n }\n\n if (socket.connecting) {\n // Send a mocked response once the socket connects, just like the real server would.\n // This preserves the correct order of events (e.g. connect, then data).\n socket.once('connect', respond)\n } else {\n /**\n * @note Reused sockets stay connected between requests and will not\n * emit \"connect\" anymore. If that's the case, respond immediately.\n */\n await respond()\n }\n },\n errorWith: (reason) => {\n if (reason instanceof Error) {\n socket.destroy(reason)\n }\n },\n passthrough: () => {\n const realSocket = socketController.passthrough(\n this.#modifyHttpHeaders(context.request)\n )\n\n if (this.emitter.listenerCount('response') > 0) {\n httpLogger.verbose(\n 'found \"response\" listener, corking socket reads'\n )\n\n /**\n * Suspend the delivery of the original response to the client\n * until the \"response\" event listeners settle. This guarantees\n * that the request promise (e.g. `await fetch()`) does not\n * resolve before the listeners are done. The real socket keeps\n * emitting data for the response parser meanwhile.\n */\n socketController.corkReads()\n\n const responseParser = new HttpResponseParser({\n onResponse: async (response) => {\n httpLogger.verbose(\n 'HTTP response parser parsed: %d %s',\n response.status,\n response.statusText\n )\n\n if (isResponseError(response)) {\n httpLogger.verbose(\n 'response is an error response, uncorking socket reads...'\n )\n\n socketController.uncorkReads()\n return\n }\n\n FetchResponse.setUrl(request.url, response)\n\n try {\n httpLogger.verbose('emitting \"response\" event')\n await this.emitter.emitAsPromise(\n new HttpResponseEvent({\n initiator,\n requestId,\n request: context.request,\n response,\n responseType: 'original',\n })\n )\n } finally {\n httpLogger.verbose('uncorking socket reads')\n socketController.uncorkReads()\n\n /**\n * @note Informational responses other than\n * \"101 Switching Protocols\" are followed by a final\n * response on the same connection. Keep gating that\n * final response on the \"response\" event listeners.\n */\n if (\n response.status < 200 &&\n response.status !== 101\n ) {\n socketController.corkReads()\n }\n }\n },\n })\n\n realSocket\n .on('data', (chunk) => responseParser.execute(chunk))\n .on('close', () => responseParser.free())\n }\n },\n },\n {\n logger: requestLogger,\n requestId,\n }\n )\n\n invariant(\n socketController['readyState'] === SocketController.PENDING,\n 'CANNOT HANDLE ALREADY HANDLED REQUEST',\n request.method,\n request.url,\n socketController['readyState']\n )\n\n /**\n * @note Create a request resolution context.\n * This is so modifications to the \"request\" in upstream interceptors\n * are correctly picked up by the underlying HTTP interceptor.\n */\n const context: HandleRequestOptions = {\n initiator,\n requestId,\n request,\n controller: requestController,\n emitter: this.emitter,\n logger: requestLogger,\n }\n\n /**\n * @note The client destroying the socket while the request\n * is still pending means the request was aborted (e.g. via\n * `AbortController`). Abort the parsed request so its\n * handling settles and late interactions with the request\n * controller become controlled errors.\n */\n abortPendingRequest = () => {\n if (\n requestController.readyState === RequestController.PENDING\n ) {\n requestAbortController.abort()\n }\n }\n\n try {\n await handleRequest(context)\n } finally {\n abortPendingRequest = undefined\n }\n },\n })\n\n // Forward the first frame to the parser.\n requestParser.execute(toBuffer(chunk))\n })\n\n socket.on('close', () => requestParser?.free())\n },\n {\n signal: controller.signal,\n }\n )\n }\n\n private async respondWith(args: {\n socket: net.Socket\n request: Request\n response: Response\n }): Promise<void> {\n const { socket, request, response } = args\n\n if (socket.destroyed) {\n return\n }\n\n if (isResponseError(response)) {\n /**\n * @note Reference the error response on the socket error so the\n * client-side interceptors (e.g. fetch) can surface it to the\n * consumer as the reason behind the failed request. Keep the\n * reference non-enumerable so the error remains observably\n * identical for the clients that expose it as-is.\n */\n socket.destroy(\n Object.defineProperty(new TypeError('Network error'), kErrorResponse, {\n value: response,\n enumerable: false,\n })\n )\n return\n }\n\n invariant(\n !socket.connecting,\n 'Failed to mock a response for \"%s %s\": socket has not connected',\n request.method,\n request.url\n )\n\n /**\n * Use native server response handling in Node.js.\n * @see https://github.com/nodejs/node/blob/13eb80f3b718452213e0fc449702aefbbfe4110f/lib/_http_server.js#L202\n */\n const incomingMessage = new IncomingMessage(socket)\n\n /**\n * @note Describe the request method so the response body is\n * handled appropriately (e.g. \"HEAD\" responses must not write\n * a body). The HTTP version is deliberately left unset: with it,\n * `ServerResponse` frames bodies of unknown length as chunked,\n * polluting the mocked response headers with \"Transfer-Encoding\"\n * the mock never specified.\n */\n incomingMessage.method = request.method\n\n const serverResponse = new ServerResponse(incomingMessage)\n\n const responseSocket = new net.Socket()\n\n responseSocket._writeGeneric = (writev, data, encoding, callback) => {\n unwrapPendingData(data, (chunk, encoding) => {\n socket.push(toBuffer(chunk), encoding)\n })\n callback?.()\n }\n\n responseSocket._destroy = (\n error: Error | null,\n callback: (error: Error | null) => void\n ) => {\n /**\n * Only destroy the socket on stream errors.\n * On a clean end, the socket is already signaled via `socket.push(null)`\n * in the main response flow. Destroying it here prematurely would prevent\n * the client from processing the response (e.g. calling `response.destroy()`).\n * @see https://github.com/mswjs/interceptors/issues/738\n */\n if (error) {\n socket.destroy()\n }\n\n callback(null)\n }\n\n responseSocket.on('drain', () => serverResponse.emit('drain'))\n serverResponse.assignSocket(responseSocket)\n\n serverResponse.removeHeader('connection')\n serverResponse.removeHeader('date')\n\n const rawResponseHeaders = getRawFetchHeaders(response.headers)\n serverResponse.writeHead(\n response.status,\n response.statusText || STATUS_CODES[response.status],\n rawResponseHeaders\n )\n\n /**\n * @note Override the socket's `_destroy` before writing the response body.\n * The underlying TCP handle (from `socket.connect()`) makes `_destroy` async\n * (`_handle.close()` callback), which delays the 'error' event. Since the real\n * TCP connection is irrelevant for mocked responses, take the synchronous path\n * so that user-initiated `response.destroy(error)` emits the error promptly.\n * This must happen before `serverResponse.end()` because the HTTP parser may\n * fire the 'response' event synchronously during `socket.push()`.\n */\n socket._destroy = function (\n error: Error | null,\n callback: (error: Error | null) => void\n ) {\n if (error) {\n /**\n * Emit the error event as a microtask instead of relying on the default\n * `process.nextTick(emitErrorNT)` from `callback(error)`. This is necessary\n * because `respondWith` runs inside a microtask (from `await reader.read()`).\n * A resolved promise continuation (from toWebResponse) is queued as\n * another microtask during the same phase. Since microtasks are drained before\n * nextTick, the test's `await` would resolve before the error event fires.\n * Using `queueMicrotask` ensures the error event is emitted within the current\n * microtask phase, before other queued microtasks.\n */\n queueMicrotask(() => this.emit('error', error))\n }\n\n callback(null)\n\n /**\n * @note `net.Socket` is constructed with `emitClose: false`, so Node's\n * stream destroy machinery does not emit `'close'` automatically; the\n * stock `net.Socket._destroy` only emits it via `_handle.close()`.\n * Since this override replaces `_destroy`, emit `'close'` here so the\n * mocked socket completes its lifecycle (otherwise consumers waiting\n * on `'close'`, like `http.ClientRequest`, hang).\n */\n process.nextTick(() => this.emit('close', error != null))\n }\n\n if (response.body) {\n const reader = response.body.getReader()\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) {\n serverResponse.end()\n break\n }\n\n if (!serverResponse.write(value)) {\n await new Promise<void>((resolve) => {\n serverResponse.once('drain', resolve)\n })\n }\n }\n } catch {\n /**\n * @note Delay the socket destruction to allow the event loop\n * to flush already-pushed response data (headers + body chunks)\n * through the HTTP parser. Without this, the socket is destroyed\n * on the same tick as `socket.push(data)` and the client never\n * reads the response.\n */\n await new Promise<void>((resolve) => process.nextTick(resolve))\n socket.destroy()\n return\n }\n } else {\n serverResponse.end()\n }\n\n /**\n * @note Self-delimiting responses (chunked, explicit \"Content-Length\",\n * or bodiless by definition) must NOT signal the end-of-stream.\n * The client parser completes them from their framing alone, and\n * ending the socket would kill the kept-alive connection that\n * agents pool and reuse for subsequent requests.\n */\n const isSelfDelimitingResponse =\n request.method === 'HEAD' ||\n response.headers.has('content-length') ||\n response.headers.has('transfer-encoding') ||\n !FetchResponse.isResponseWithBody(response.status)\n\n if (\n /**\n * @note A non-2xx response to a \"CONNECT\" request means the proxy\n * refused the tunnel. Real proxies terminate the connection after\n * sending such a response, regardless of its framing.\n */\n (request.method === 'CONNECT' && !response.ok) ||\n (request.method !== 'CONNECT' && !isSelfDelimitingResponse)\n ) {\n /**\n * @note Defer the end-of-stream signal so the HTTP parser has a chance\n * to process already-pushed response data and fire the 'response' event\n * before the socket is ended. Without this, the parser marks the response\n * as \"complete\" before the client can interact with it (e.g. `response.destroy()`).\n */\n await new Promise<void>((resolve) => process.nextTick(resolve))\n socket.push(null)\n }\n }\n\n #modifyHttpHeaders(request: Request): FlushPendingDataFunction {\n const transformRequestMessage = (\n httpMessage: string | Buffer,\n encoding?: BufferEncoding | 'buffer'\n ): string | Buffer => {\n /**\n * @note Socket can write a buffer (e.g. uploaded file) even before\n * it writes the HTTP message. Bypass those cases.\n */\n if (encoding === 'buffer') {\n return httpMessage\n }\n\n const parts = httpMessage.toString(encoding).split('\\r\\n')\n const headersEndIndex = parts.findIndex((field) => field === '')\n const httpMessageHeaderPairs = parts.slice(1, headersEndIndex)\n\n // Extract raw [name, value] tuples from the wire format so they\n // can be compared against the request's raw fetch headers.\n const httpMessageRawHeaders = httpMessageHeaderPairs.map(\n (line): [string, string] => {\n const separatorIndex = line.indexOf(': ')\n return [line.slice(0, separatorIndex), line.slice(separatorIndex + 2)]\n }\n )\n\n const requestRawHeaders = getRawFetchHeaders(request.headers)\n\n // If the raw headers from the outgoing HTTP message and the request\n // headers are identical, send the message as-is to avoid the cost\n // (and side effects) of reserializing the headers block.\n const headersUnchanged =\n httpMessageRawHeaders.length === requestRawHeaders.length &&\n httpMessageRawHeaders.every((tuple, index) => {\n const requestTuple = requestRawHeaders[index]\n return tuple[0] === requestTuple[0] && tuple[1] === requestTuple[1]\n })\n\n if (headersUnchanged) {\n return httpMessage\n }\n\n const httpMessageHeaders = FetchResponse.parseRawHeaders(\n httpMessageHeaderPairs.flatMap((header) => header.split(': '))\n )\n\n const visitedHeaders = new Set<string>()\n\n for (const [headerName] of requestRawHeaders) {\n const normalizedHeaderName = headerName.toLowerCase()\n\n if (visitedHeaders.has(normalizedHeaderName)) {\n continue\n }\n\n visitedHeaders.add(normalizedHeaderName)\n\n /**\n * @note Forbidden Fetch headers (e.g. Host, Origin, Connection)\n * are stripped from `request.headers` but remain in the raw\n * headers list. Skip them so the original values from the\n * outgoing HTTP message are preserved.\n */\n const headerValue = request.headers.get(headerName)\n if (headerValue === null) {\n continue\n }\n\n // Use the merged value from Headers to correctly handle\n // appended headers (e.g. \"1, 2\" instead of just \"2\").\n httpMessageHeaders.set(headerName, headerValue)\n }\n\n visitedHeaders.clear()\n\n const httpMessageHeadersString = Array.from(httpMessageHeaders)\n .map(([name, value]) => `${name}: ${value}`)\n .join('\\r\\n')\n parts.splice(1, headersEndIndex - 1, httpMessageHeadersString)\n\n return parts.join('\\r\\n')\n }\n\n return (pendingData, encoding, callback) => {\n if (Array.isArray(pendingData)) {\n pendingData[0].chunk = transformRequestMessage(\n pendingData[0].chunk,\n pendingData[0].encoding\n )\n } else {\n pendingData = transformRequestMessage(pendingData, encoding)\n }\n\n callback(pendingData)\n }\n }\n}\n"],"mappings":"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"}