From d09bc5402de5a9478b22ff63756f9358b0b3e1d9 Mon Sep 17 00:00:00 2001
From: "Node.js GitHub Bot" <github-bot@iojs.org>
Date: Mon, 8 Aug 2022 04:41:22 -0400
Subject: [PATCH] deps: update undici to 5.8.1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

PR-URL: https://github.com/nodejs/node/pull/44158
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
Reviewed-By: Feng Yu <F3n67u@outlook.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
---
 .../docs/best-practices/mocking-request.md    | 18 ++--
 deps/undici/src/lib/core/connect.js           | 33 +++++--
 deps/undici/src/lib/fetch/body.js             | 13 ++-
 deps/undici/src/lib/fetch/dataURL.js          |  2 +-
 deps/undici/src/lib/fetch/index.js            | 18 ++--
 deps/undici/src/lib/fetch/request.js          | 10 +--
 deps/undici/src/lib/fetch/response.js         | 15 ++--
 deps/undici/src/lib/fetch/util.js             | 10 ++-
 deps/undici/src/lib/fetch/webidl.js           |  5 +-
 deps/undici/src/lib/mock/mock-utils.js        | 29 +++++--
 deps/undici/src/package.json                  |  3 +-
 deps/undici/src/types/mock-interceptor.d.ts   |  2 +-
 deps/undici/src/types/pool-stats.d.ts         | 19 +++++
 deps/undici/src/types/pool.d.ts               |  4 +
 deps/undici/undici.js                         | 85 ++++++++++++++-----
 15 files changed, 195 insertions(+), 71 deletions(-)
 create mode 100644 deps/undici/src/types/pool-stats.d.ts

diff --git a/deps/undici/src/docs/best-practices/mocking-request.md b/deps/undici/src/docs/best-practices/mocking-request.md
index b98a450a32e2..695439274449 100644
--- a/deps/undici/src/docs/best-practices/mocking-request.md
+++ b/deps/undici/src/docs/best-practices/mocking-request.md
@@ -1,6 +1,6 @@
 # Mocking Request
 
-Undici have its own mocking [utility](../api/MockAgent.md). It allow us to intercept undici HTTP request and return mocked value instead. It can be useful for testing purposes.
+Undici has its own mocking [utility](../api/MockAgent.md). It allow us to intercept undici HTTP requests and return mocked values instead. It can be useful for testing purposes.
 
 Example:
 
@@ -8,7 +8,7 @@ Example:
 // bank.mjs
 import { request } from 'undici'
 
-export async function bankTransfer(recepient, amount) {
+export async function bankTransfer(recipient, amount) {
   const { body } = await request('http://localhost:3000/bank-transfer',
     {
       method: 'POST',
@@ -16,7 +16,7 @@ export async function bankTransfer(recepient, amount) {
         'X-TOKEN-SECRET': 'SuperSecretToken',
       },
       body: JSON.stringify({
-        recepient,
+        recipient,
         amount
       })
     }
@@ -48,7 +48,7 @@ mockPool.intercept({
     'X-TOKEN-SECRET': 'SuperSecretToken',
   },
   body: JSON.stringify({
-    recepient: '1234567890',
+    recipient: '1234567890',
     amount: '100'
   })
 }).reply(200, {
@@ -77,7 +77,7 @@ Explore other MockAgent functionality [here](../api/MockAgent.md)
 
 ## Debug Mock Value
 
-When the interceptor we wrote are not the same undici will automatically call real HTTP request. To debug our mock value use `mockAgent.disableNetConnect()`
+When the interceptor and the request options are not the same, undici will automatically make a real HTTP request. To prevent real requests from being made, use `mockAgent.disableNetConnect()`:
 
 ```js
 const mockAgent = new MockAgent();
@@ -89,7 +89,7 @@ mockAgent.disableNetConnect()
 const mockPool = mockAgent.get('http://localhost:3000');
 
 mockPool.intercept({
-  path: '/bank-tanfer',
+  path: '/bank-transfer',
   method: 'POST',
 }).reply(200, {
   message: 'transaction processed'
@@ -103,7 +103,7 @@ const badRequest = await bankTransfer('1234567890', '100')
 
 ## Reply with data based on request
 
-If the mocked response needs to be dynamically derived from the request parameters, you can provide a function instead of an object to `reply`
+If the mocked response needs to be dynamically derived from the request parameters, you can provide a function instead of an object to `reply`:
 
 ```js
 mockPool.intercept({
@@ -113,7 +113,7 @@ mockPool.intercept({
     'X-TOKEN-SECRET': 'SuperSecretToken',
   },
   body: JSON.stringify({
-    recepient: '1234567890',
+    recipient: '1234567890',
     amount: '100'
   })
 }).reply(200, (opts) => {
@@ -129,7 +129,7 @@ in this case opts will be
 {
   method: 'POST',
   headers: { 'X-TOKEN-SECRET': 'SuperSecretToken' },
-  body: '{"recepient":"1234567890","amount":"100"}',
+  body: '{"recipient":"1234567890","amount":"100"}',
   origin: 'http://localhost:3000',
   path: '/bank-transfer'
 }
diff --git a/deps/undici/src/lib/core/connect.js b/deps/undici/src/lib/core/connect.js
index 57667a1314af..e9b456f88319 100644
--- a/deps/undici/src/lib/core/connect.js
+++ b/deps/undici/src/lib/core/connect.js
@@ -75,14 +75,12 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
       })
     }
 
-    const timeoutId = timeout
-      ? setTimeout(onConnectTimeout, timeout, socket)
-      : null
+    const cancelTimeout = setupTimeout(() => onConnectTimeout(socket), timeout)
 
     socket
       .setNoDelay(true)
       .once(protocol === 'https:' ? 'secureConnect' : 'connect', function () {
-        clearTimeout(timeoutId)
+        cancelTimeout()
 
         if (callback) {
           const cb = callback
@@ -91,7 +89,7 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
         }
       })
       .on('error', function (err) {
-        clearTimeout(timeoutId)
+        cancelTimeout()
 
         if (callback) {
           const cb = callback
@@ -104,6 +102,31 @@ function buildConnector ({ maxCachedSessions, socketPath, timeout, ...opts }) {
   }
 }
 
+function setupTimeout (onConnectTimeout, timeout) {
+  if (!timeout) {
+    return () => {}
+  }
+
+  let s1 = null
+  let s2 = null
+  const timeoutId = setTimeout(() => {
+    // setImmediate is added to make sure that we priotorise socket error events over timeouts
+    s1 = setImmediate(() => {
+      if (process.platform === 'win32') {
+        // Windows needs an extra setImmediate probably due to implementation differences in the socket logic
+        s2 = setImmediate(() => onConnectTimeout())
+      } else {
+        onConnectTimeout()
+      }
+    })
+  }, timeout)
+  return () => {
+    clearTimeout(timeoutId)
+    clearImmediate(s1)
+    clearImmediate(s2)
+  }
+}
+
 function onConnectTimeout (socket) {
   util.destroy(socket, new ConnectTimeoutError())
 }
diff --git a/deps/undici/src/lib/fetch/body.js b/deps/undici/src/lib/fetch/body.js
index 2a9f1c83d888..08d22310a38d 100644
--- a/deps/undici/src/lib/fetch/body.js
+++ b/deps/undici/src/lib/fetch/body.js
@@ -404,7 +404,18 @@ function bodyMixinMethods (instance) {
         // 1. Let entries be the result of parsing bytes.
         let entries
         try {
-          entries = new URLSearchParams(await this.text())
+          let text = ''
+          // application/x-www-form-urlencoded parser will keep the BOM.
+          // https://url.spec.whatwg.org/#concept-urlencoded-parser
+          const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true })
+          for await (const chunk of consumeBody(this[kState].body)) {
+            if (!isUint8Array(chunk)) {
+              throw new TypeError('Expected Uint8Array chunk')
+            }
+            text += textDecoder.decode(chunk, { stream: true })
+          }
+          text += textDecoder.decode()
+          entries = new URLSearchParams(text)
         } catch (err) {
           // istanbul ignore next: Unclear when new URLSearchParams can fail on a string.
           // 2. If entries is failure, then throw a TypeError.
diff --git a/deps/undici/src/lib/fetch/dataURL.js b/deps/undici/src/lib/fetch/dataURL.js
index 5eb0a514aed2..cad44853e165 100644
--- a/deps/undici/src/lib/fetch/dataURL.js
+++ b/deps/undici/src/lib/fetch/dataURL.js
@@ -255,7 +255,7 @@ function percentDecode (input) {
   }
 
   // 3. Return output.
-  return Uint8Array.of(...output)
+  return Uint8Array.from(output)
 }
 
 // https://mimesniff.spec.whatwg.org/#parse-a-mime-type
diff --git a/deps/undici/src/lib/fetch/index.js b/deps/undici/src/lib/fetch/index.js
index cf91a5d378e9..f9b09547edbc 100644
--- a/deps/undici/src/lib/fetch/index.js
+++ b/deps/undici/src/lib/fetch/index.js
@@ -33,7 +33,8 @@ const {
   isBlobLike,
   sameOrigin,
   isCancelled,
-  isAborted
+  isAborted,
+  isErrorLike
 } = require('./util')
 const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
 const assert = require('assert')
@@ -1854,7 +1855,7 @@ async function httpNetworkFetch (
       timingInfo.decodedBodySize += bytes?.byteLength ?? 0
 
       // 6. If bytes is failure, then terminate fetchParams’s controller.
-      if (bytes instanceof Error) {
+      if (isErrorLike(bytes)) {
         fetchParams.controller.terminate(bytes)
         return
       }
@@ -1894,7 +1895,7 @@ async function httpNetworkFetch (
       // 3. Otherwise, if stream is readable, error stream with a TypeError.
       if (isReadable(stream)) {
         fetchParams.controller.controller.error(new TypeError('terminated', {
-          cause: reason instanceof Error ? reason : undefined
+          cause: isErrorLike(reason) ? reason : undefined
         }))
       }
     }
@@ -1942,14 +1943,17 @@ async function httpNetworkFetch (
           }
 
           let codings = []
+          let location = ''
 
           const headers = new Headers()
           for (let n = 0; n < headersList.length; n += 2) {
-            const key = headersList[n + 0].toString()
-            const val = headersList[n + 1].toString()
+            const key = headersList[n + 0].toString('latin1')
+            const val = headersList[n + 1].toString('latin1')
 
             if (key.toLowerCase() === 'content-encoding') {
               codings = val.split(',').map((x) => x.trim())
+            } else if (key.toLowerCase() === 'location') {
+              location = val
             }
 
             headers.append(key, val)
@@ -1960,7 +1964,7 @@ async function httpNetworkFetch (
           const decoders = []
 
           // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
-          if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status)) {
+          if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !(request.redirect === 'follow' && location)) {
             for (const coding of codings) {
               if (/(x-)?gzip/.test(coding)) {
                 decoders.push(zlib.createGunzip())
@@ -1980,7 +1984,7 @@ async function httpNetworkFetch (
             statusText,
             headersList: headers[kHeadersList],
             body: decoders.length
-              ? pipeline(this.body, ...decoders, () => {})
+              ? pipeline(this.body, ...decoders, () => { })
               : this.body.on('error', () => {})
           })
 
diff --git a/deps/undici/src/lib/fetch/request.js b/deps/undici/src/lib/fetch/request.js
index 7e1b3d8eb1d0..7fda8d90b28b 100644
--- a/deps/undici/src/lib/fetch/request.js
+++ b/deps/undici/src/lib/fetch/request.js
@@ -367,9 +367,9 @@ class Request {
       }
 
       if (signal.aborted) {
-        ac.abort()
+        ac.abort(signal.reason)
       } else {
-        const abort = () => ac.abort()
+        const abort = () => ac.abort(signal.reason)
         signal.addEventListener('abort', abort, { once: true })
         requestFinalizer.register(this, { signal, abort })
       }
@@ -726,12 +726,12 @@ class Request {
     // 4. Make clonedRequestObject’s signal follow this’s signal.
     const ac = new AbortController()
     if (this.signal.aborted) {
-      ac.abort()
+      ac.abort(this.signal.reason)
     } else {
       this.signal.addEventListener(
         'abort',
-        function () {
-          ac.abort()
+        () => {
+          ac.abort(this.signal.reason)
         },
         { once: true }
       )
diff --git a/deps/undici/src/lib/fetch/response.js b/deps/undici/src/lib/fetch/response.js
index 4649a5da9070..526259478d40 100644
--- a/deps/undici/src/lib/fetch/response.js
+++ b/deps/undici/src/lib/fetch/response.js
@@ -10,7 +10,8 @@ const {
   isCancelled,
   isAborted,
   isBlobLike,
-  serializeJavascriptValueToJSONString
+  serializeJavascriptValueToJSONString,
+  isErrorLike
 } = require('./util')
 const {
   redirectStatus,
@@ -347,15 +348,15 @@ function makeResponse (init) {
 }
 
 function makeNetworkError (reason) {
+  const isError = isErrorLike(reason)
   return makeResponse({
     type: 'error',
     status: 0,
-    error:
-      reason instanceof Error
-        ? reason
-        : new Error(reason ? String(reason) : reason, {
-          cause: reason instanceof Error ? reason : undefined
-        }),
+    error: isError
+      ? reason
+      : new Error(reason ? String(reason) : reason, {
+        cause: isError ? reason : undefined
+      }),
     aborted: reason && reason.name === 'AbortError'
   })
 }
diff --git a/deps/undici/src/lib/fetch/util.js b/deps/undici/src/lib/fetch/util.js
index 17c68162980f..9806e331871c 100644
--- a/deps/undici/src/lib/fetch/util.js
+++ b/deps/undici/src/lib/fetch/util.js
@@ -82,6 +82,13 @@ function isFileLike (object) {
   )
 }
 
+function isErrorLike (object) {
+  return object instanceof Error || (
+    object?.constructor?.name === 'Error' ||
+    object?.constructor?.name === 'DOMException'
+  )
+}
+
 // Check whether |statusText| is a ByteString and
 // matches the Reason-Phrase token production.
 // RFC 2616: https://tools.ietf.org/html/rfc2616
@@ -469,5 +476,6 @@ module.exports = {
   makeIterator,
   isValidHeaderName,
   isValidHeaderValue,
-  hasOwn
+  hasOwn,
+  isErrorLike
 }
diff --git a/deps/undici/src/lib/fetch/webidl.js b/deps/undici/src/lib/fetch/webidl.js
index f9a780ccaa74..293199e8f9b4 100644
--- a/deps/undici/src/lib/fetch/webidl.js
+++ b/deps/undici/src/lib/fetch/webidl.js
@@ -388,8 +388,9 @@ webidl.converters.DOMString = function (V, opts = {}) {
   return String(V)
 }
 
+// Check for 0 or more characters outside of the latin1 range.
 // eslint-disable-next-line no-control-regex
-const isNotLatin1 = /[^\u0000-\u00ff]/
+const isLatin1 = /^[\u0000-\u00ff]{0,}$/
 
 // https://webidl.spec.whatwg.org/#es-ByteString
 webidl.converters.ByteString = function (V) {
@@ -399,7 +400,7 @@ webidl.converters.ByteString = function (V) {
 
   // 2. If the value of any element of x is greater than
   //    255, then throw a TypeError.
-  if (isNotLatin1.test(x)) {
+  if (!isLatin1.test(x)) {
     throw new TypeError('Argument is not a ByteString')
   }
 
diff --git a/deps/undici/src/lib/mock/mock-utils.js b/deps/undici/src/lib/mock/mock-utils.js
index 80052223f8fb..7e115f83b4d5 100644
--- a/deps/undici/src/lib/mock/mock-utils.js
+++ b/deps/undici/src/lib/mock/mock-utils.js
@@ -38,7 +38,7 @@ function lowerCaseEntries (headers) {
 function getHeaderByName (headers, key) {
   if (Array.isArray(headers)) {
     for (let i = 0; i < headers.length; i += 2) {
-      if (headers[i] === key) {
+      if (headers[i].toLocaleLowerCase() === key.toLocaleLowerCase()) {
         return headers[i + 1]
       }
     }
@@ -47,19 +47,24 @@ function getHeaderByName (headers, key) {
   } else if (typeof headers.get === 'function') {
     return headers.get(key)
   } else {
-    return headers[key]
+    return lowerCaseEntries(headers)[key.toLocaleLowerCase()]
   }
 }
 
+/** @param {string[]} headers */
+function buildHeadersFromArray (headers) { // fetch HeadersList
+  const clone = headers.slice()
+  const entries = []
+  for (let index = 0; index < clone.length; index += 2) {
+    entries.push([clone[index], clone[index + 1]])
+  }
+  return Object.fromEntries(entries)
+}
+
 function matchHeaders (mockDispatch, headers) {
   if (typeof mockDispatch.headers === 'function') {
     if (Array.isArray(headers)) { // fetch HeadersList
-      const clone = headers.slice()
-      const entries = []
-      for (let index = 0; index < clone.length; index += 2) {
-        entries.push([clone[index], clone[index + 1]])
-      }
-      headers = Object.fromEntries(entries)
+      headers = buildHeadersFromArray(headers)
     }
     return mockDispatch.headers(headers ? lowerCaseEntries(headers) : {})
   }
@@ -284,7 +289,13 @@ function mockDispatch (opts, handler) {
   }
 
   function handleReply (mockDispatches) {
-    const responseData = getResponseData(typeof data === 'function' ? data(opts) : data)
+    // fetch's HeadersList is a 1D string array
+    const optsHeaders = Array.isArray(opts.headers)
+      ? buildHeadersFromArray(opts.headers)
+      : opts.headers
+    const responseData = getResponseData(
+      typeof data === 'function' ? data({ ...opts, headers: optsHeaders }) : data
+    )
     const responseHeaders = generateKeyValues(headers)
     const responseTrailers = generateKeyValues(trailers)
 
diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json
index 1fde040055fa..4ac0eb8863d1 100644
--- a/deps/undici/src/package.json
+++ b/deps/undici/src/package.json
@@ -1,6 +1,6 @@
 {
   "name": "undici",
-  "version": "5.8.0",
+  "version": "5.8.1",
   "description": "An HTTP/1.1 client, written from scratch for Node.js",
   "homepage": "https://undici.nodejs.org",
   "bugs": {
@@ -67,6 +67,7 @@
     "@sinonjs/fake-timers": "^9.1.2",
     "@types/node": "^17.0.29",
     "abort-controller": "^3.0.0",
+    "atomic-sleep": "^1.0.0",
     "busboy": "^1.6.0",
     "chai": "^4.3.4",
     "chai-as-promised": "^7.1.1",
diff --git a/deps/undici/src/types/mock-interceptor.d.ts b/deps/undici/src/types/mock-interceptor.d.ts
index 8812960573f3..87eedcd40605 100644
--- a/deps/undici/src/types/mock-interceptor.d.ts
+++ b/deps/undici/src/types/mock-interceptor.d.ts
@@ -74,7 +74,7 @@ declare namespace MockInterceptor {
     origin: string;
     method: string;
     body?: BodyInit | Dispatcher.DispatchOptions['body'];
-    headers: Headers;
+    headers: Headers | Record<string, string>;
     maxRedirections: number;
   }
 
diff --git a/deps/undici/src/types/pool-stats.d.ts b/deps/undici/src/types/pool-stats.d.ts
new file mode 100644
index 000000000000..807e68f1b81d
--- /dev/null
+++ b/deps/undici/src/types/pool-stats.d.ts
@@ -0,0 +1,19 @@
+import Pool = require("./pool")
+
+export = PoolStats
+
+declare class PoolStats {
+  constructor(pool: Pool);
+  /** Number of open socket connections in this pool. */
+  connected: number;
+  /** Number of open socket connections in this pool that do not have an active request. */
+  free: number;
+  /** Number of pending requests across all clients in this pool. */
+  pending: number;
+  /** Number of queued requests across all clients in this pool. */
+  queued: number;
+  /** Number of currently active requests across all clients in this pool. */
+  running: number;
+  /** Number of active, pending, or queued requests across all clients in this pool. */
+  size: number;
+}
diff --git a/deps/undici/src/types/pool.d.ts b/deps/undici/src/types/pool.d.ts
index 82aeb376cd23..af7fb94a9a68 100644
--- a/deps/undici/src/types/pool.d.ts
+++ b/deps/undici/src/types/pool.d.ts
@@ -1,5 +1,6 @@
 import Client = require('./client')
 import Dispatcher = require('./dispatcher')
+import TPoolStats = require('./pool-stats')
 import { URL } from 'url'
 
 export = Pool
@@ -10,9 +11,12 @@ declare class Pool extends Dispatcher {
   closed: boolean;
   /** `true` after `pool.destroyed()` has been called or `pool.close()` has been called and the pool shutdown has completed. */
   destroyed: boolean;
+  /** Aggregate stats for a Pool. */
+  readonly stats: TPoolStats;
 }
 
 declare namespace Pool {
+  export type PoolStats = TPoolStats;
   export interface Options extends Client.Options {
     /** Default: `(origin, opts) => new Client(origin, opts)`. */
     factory?(origin: URL, opts: object): Dispatcher;
diff --git a/deps/undici/undici.js b/deps/undici/undici.js
index f59f177536a3..123b51b4d306 100644
--- a/deps/undici/undici.js
+++ b/deps/undici/undici.js
@@ -1281,10 +1281,10 @@ var require_webidl = __commonJS({
       }
       return String(V);
     };
-    var isNotLatin1 = /[^\u0000-\u00ff]/;
+    var isLatin1 = /^[\u0000-\u00ff]{0,}$/;
     webidl.converters.ByteString = function(V) {
       const x = webidl.converters.DOMString(V);
-      if (isNotLatin1.test(x)) {
+      if (!isLatin1.test(x)) {
         throw new TypeError("Argument is not a ByteString");
       }
       return x;
@@ -1671,6 +1671,9 @@ var require_util2 = __commonJS({
       }
       return object instanceof File || object && (typeof object.stream === "function" || typeof object.arrayBuffer === "function") && /^(File)$/.test(object[Symbol.toStringTag]);
     }
+    function isErrorLike(object) {
+      return object instanceof Error || (object?.constructor?.name === "Error" || object?.constructor?.name === "DOMException");
+    }
     function isValidReasonPhrase(statusText) {
       for (let i = 0; i < statusText.length; ++i) {
         const c = statusText.charCodeAt(i);
@@ -1877,7 +1880,8 @@ var require_util2 = __commonJS({
       makeIterator,
       isValidHeaderName,
       isValidHeaderValue,
-      hasOwn
+      hasOwn,
+      isErrorLike
     };
   }
 });
@@ -2300,7 +2304,16 @@ Content-Type: ${value.type || "application/octet-stream"}\r
           } else if (/application\/x-www-form-urlencoded/.test(contentType)) {
             let entries;
             try {
-              entries = new URLSearchParams(await this.text());
+              let text = "";
+              const textDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
+              for await (const chunk of consumeBody(this[kState].body)) {
+                if (!isUint8Array(chunk)) {
+                  throw new TypeError("Expected Uint8Array chunk");
+                }
+                text += textDecoder.decode(chunk, { stream: true });
+              }
+              text += textDecoder.decode();
+              entries = new URLSearchParams(text);
             } catch (err) {
               throw Object.assign(new TypeError(), { cause: err });
             }
@@ -2792,16 +2805,16 @@ var require_connect = __commonJS({
             host: hostname
           });
         }
-        const timeoutId = timeout ? setTimeout(onConnectTimeout, timeout, socket) : null;
+        const cancelTimeout = setupTimeout(() => onConnectTimeout(socket), timeout);
         socket.setNoDelay(true).once(protocol === "https:" ? "secureConnect" : "connect", function() {
-          clearTimeout(timeoutId);
+          cancelTimeout();
           if (callback) {
             const cb = callback;
             callback = null;
             cb(null, this);
           }
         }).on("error", function(err) {
-          clearTimeout(timeoutId);
+          cancelTimeout();
           if (callback) {
             const cb = callback;
             callback = null;
@@ -2811,6 +2824,28 @@ var require_connect = __commonJS({
         return socket;
       };
     }
+    function setupTimeout(onConnectTimeout2, timeout) {
+      if (!timeout) {
+        return () => {
+        };
+      }
+      let s1 = null;
+      let s2 = null;
+      const timeoutId = setTimeout(() => {
+        s1 = setImmediate(() => {
+          if (process.platform === "win32") {
+            s2 = setImmediate(() => onConnectTimeout2());
+          } else {
+            onConnectTimeout2();
+          }
+        });
+      }, timeout);
+      return () => {
+        clearTimeout(timeoutId);
+        clearImmediate(s1);
+        clearImmediate(s2);
+      };
+    }
     function onConnectTimeout(socket) {
       util.destroy(socket, new ConnectTimeoutError());
     }
@@ -5047,7 +5082,8 @@ var require_response = __commonJS({
       isCancelled,
       isAborted,
       isBlobLike,
-      serializeJavascriptValueToJSONString
+      serializeJavascriptValueToJSONString,
+      isErrorLike
     } = require_util2();
     var {
       redirectStatus,
@@ -5245,11 +5281,12 @@ var require_response = __commonJS({
       };
     }
     function makeNetworkError(reason) {
+      const isError = isErrorLike(reason);
       return makeResponse({
         type: "error",
         status: 0,
-        error: reason instanceof Error ? reason : new Error(reason ? String(reason) : reason, {
-          cause: reason instanceof Error ? reason : void 0
+        error: isError ? reason : new Error(reason ? String(reason) : reason, {
+          cause: isError ? reason : void 0
         }),
         aborted: reason && reason.name === "AbortError"
       });
@@ -5586,9 +5623,9 @@ var require_request2 = __commonJS({
             throw new TypeError("Failed to construct 'Request': member signal is not of type AbortSignal.");
           }
           if (signal.aborted) {
-            ac.abort();
+            ac.abort(signal.reason);
           } else {
-            const abort = () => ac.abort();
+            const abort = () => ac.abort(signal.reason);
             signal.addEventListener("abort", abort, { once: true });
             requestFinalizer.register(this, { signal, abort });
           }
@@ -5767,10 +5804,10 @@ var require_request2 = __commonJS({
         clonedRequestObject[kHeaders][kRealm] = this[kHeaders][kRealm];
         const ac = new AbortController();
         if (this.signal.aborted) {
-          ac.abort();
+          ac.abort(this.signal.reason);
         } else {
-          this.signal.addEventListener("abort", function() {
-            ac.abort();
+          this.signal.addEventListener("abort", () => {
+            ac.abort(this.signal.reason);
           }, { once: true });
         }
         clonedRequestObject[kSignal] = ac.signal;
@@ -6035,7 +6072,7 @@ var require_dataURL = __commonJS({
           i += 2;
         }
       }
-      return Uint8Array.of(...output);
+      return Uint8Array.from(output);
     }
     function parseMIMEType(input) {
       input = input.trim();
@@ -6182,7 +6219,8 @@ var require_fetch = __commonJS({
       isBlobLike,
       sameOrigin,
       isCancelled,
-      isAborted
+      isAborted,
+      isErrorLike
     } = require_util2();
     var { kState, kHeaders, kGuard, kRealm } = require_symbols2();
     var assert = require("assert");
@@ -6945,7 +6983,7 @@ var require_fetch = __commonJS({
             return;
           }
           timingInfo.decodedBodySize += bytes?.byteLength ?? 0;
-          if (bytes instanceof Error) {
+          if (isErrorLike(bytes)) {
             fetchParams.controller.terminate(bytes);
             return;
           }
@@ -6968,7 +7006,7 @@ var require_fetch = __commonJS({
         } else {
           if (isReadable(stream)) {
             fetchParams.controller.controller.error(new TypeError("terminated", {
-              cause: reason instanceof Error ? reason : void 0
+              cause: isErrorLike(reason) ? reason : void 0
             }));
           }
         }
@@ -7003,18 +7041,21 @@ var require_fetch = __commonJS({
               return;
             }
             let codings = [];
+            let location = "";
             const headers = new Headers();
             for (let n = 0; n < headersList.length; n += 2) {
-              const key = headersList[n + 0].toString();
-              const val = headersList[n + 1].toString();
+              const key = headersList[n + 0].toString("latin1");
+              const val = headersList[n + 1].toString("latin1");
               if (key.toLowerCase() === "content-encoding") {
                 codings = val.split(",").map((x) => x.trim());
+              } else if (key.toLowerCase() === "location") {
+                location = val;
               }
               headers.append(key, val);
             }
             this.body = new Readable({ read: resume });
             const decoders = [];
-            if (request.method !== "HEAD" && request.method !== "CONNECT" && !nullBodyStatus.includes(status)) {
+            if (request.method !== "HEAD" && request.method !== "CONNECT" && !nullBodyStatus.includes(status) && !(request.redirect === "follow" && location)) {
               for (const coding of codings) {
                 if (/(x-)?gzip/.test(coding)) {
                   decoders.push(zlib.createGunzip());
