@rspack/dev-server 2.0.3 → 2.2.0

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.
package/dist/0~debug.js CHANGED
@@ -1,7 +1,7 @@
1
- import { __webpack_require__ } from "./465.js";
2
- import "./465.js";
1
+ import { __webpack_require__ } from "./619.js";
2
+ import "./619.js";
3
3
  __webpack_require__.add({
4
- "./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/browser.js" (module, exports, __webpack_require__) {
4
+ "./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/browser.js" (module, exports, __webpack_require__) {
5
5
  exports.formatArgs = formatArgs;
6
6
  exports.save = save;
7
7
  exports.load = load;
@@ -134,7 +134,7 @@ __webpack_require__.add({
134
134
  return localStorage;
135
135
  } catch (error) {}
136
136
  }
137
- module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/common.js")(exports);
137
+ module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/common.js")(exports);
138
138
  const { formatters } = module.exports;
139
139
  formatters.j = function(v) {
140
140
  try {
@@ -144,7 +144,7 @@ __webpack_require__.add({
144
144
  }
145
145
  };
146
146
  },
147
- "./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/common.js" (module, __unused_rspack_exports, __webpack_require__) {
147
+ "./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/common.js" (module, __unused_rspack_exports, __webpack_require__) {
148
148
  function setup(env) {
149
149
  createDebug.debug = createDebug;
150
150
  createDebug.default = createDebug;
@@ -286,11 +286,11 @@ __webpack_require__.add({
286
286
  }
287
287
  module.exports = setup;
288
288
  },
289
- "./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/index.js" (module, __unused_rspack_exports, __webpack_require__) {
290
- if ("u" < typeof process || 'renderer' === process.type || true === process.browser || process.__nwjs) module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/browser.js");
291
- else module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/node.js");
289
+ "./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/index.js" (module, __unused_rspack_exports, __webpack_require__) {
290
+ if ("u" < typeof process || 'renderer' === process.type || true === process.browser || process.__nwjs) module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/browser.js");
291
+ else module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/node.js");
292
292
  },
293
- "./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/node.js" (module, exports, __webpack_require__) {
293
+ "./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/node.js" (module, exports, __webpack_require__) {
294
294
  const tty = __webpack_require__("tty");
295
295
  const util = __webpack_require__("util");
296
296
  exports.init = init;
@@ -428,7 +428,7 @@ __webpack_require__.add({
428
428
  const keys = Object.keys(exports.inspectOpts);
429
429
  for(let i = 0; i < keys.length; i++)debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
430
430
  }
431
- module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/common.js")(exports);
431
+ module.exports = __webpack_require__("./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/common.js")(exports);
432
432
  const { formatters } = module.exports;
433
433
  formatters.o = function(v) {
434
434
  this.inspectOpts.colors = this.useColors;
@@ -5,13 +5,14 @@ import node_http2 from "node:http2";
5
5
  import { EventEmitter } from "node:events";
6
6
  import "node:net";
7
7
  import "node:stream";
8
+ import { styleText } from "node:util";
8
9
  import { URL as external_node_url_URL } from "node:url";
9
10
  import { URL as external_url_URL } from "url";
10
11
  import "node:zlib";
11
12
  import "node:querystring";
12
- import { __webpack_require__ } from "./465.js";
13
+ import { __webpack_require__ } from "./619.js";
13
14
  import "./0~debug.js";
14
- import "./465.js";
15
+ import "./619.js";
15
16
  __webpack_require__.add({
16
17
  "./node_modules/.pnpm/braces@3.0.3/node_modules/braces/index.js" (module, __unused_rspack_exports, __webpack_require__) {
17
18
  const stringify = __webpack_require__("./node_modules/.pnpm/braces@3.0.3/node_modules/braces/lib/stringify.js");
@@ -2796,6 +2797,7 @@ __webpack_require__.add({
2796
2797
  }
2797
2798
  });
2798
2799
  const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i;
2800
+ const transferEncodingConnectionToken = /(^|,)\s*transfer-encoding\s*($|,)/i;
2799
2801
  const defaultAgents = {
2800
2802
  http: new node_http.Agent({
2801
2803
  keepAlive: true,
@@ -2809,6 +2811,16 @@ const defaultAgents = {
2809
2811
  })
2810
2812
  };
2811
2813
  const isSSL = /^https|wss/;
2814
+ function forceConnectionCloseForTransferEncoding(headers) {
2815
+ let carriesTransferEncoding = false;
2816
+ for(const key in headers)if (void 0 !== headers[key] && "transfer-encoding" === key.toLowerCase()) {
2817
+ carriesTransferEncoding = true;
2818
+ break;
2819
+ }
2820
+ const connection = headers.connection;
2821
+ const connectionMarksTransferEncoding = "string" == typeof connection && transferEncodingConnectionToken.test(connection);
2822
+ if (carriesTransferEncoding || connectionMarksTransferEncoding) headers.connection = "close";
2823
+ }
2812
2824
  const HTTP2_HEADER_BLACKLIST = [
2813
2825
  ":method",
2814
2826
  ":path",
@@ -2832,6 +2844,10 @@ function setupOutgoing(outgoing, options, req, forward) {
2832
2844
  const value = options[forward || "target"][e];
2833
2845
  if (void 0 !== value) outgoing[e] = value;
2834
2846
  }
2847
+ if (void 0 === outgoing.host && "string" == typeof outgoing.hostname) {
2848
+ const bracketedHost = outgoing.hostname.includes(":") && !outgoing.hostname.startsWith("[") ? `[${outgoing.hostname}]` : outgoing.hostname;
2849
+ outgoing.host = outgoing.port ? `${bracketedHost}:${outgoing.port}` : bracketedHost;
2850
+ }
2835
2851
  outgoing.method = options.method || req.method;
2836
2852
  outgoing.headers = {
2837
2853
  ...req.headers
@@ -2853,6 +2869,8 @@ function setupOutgoing(outgoing, options, req, forward) {
2853
2869
  outgoing.headers = outgoing.headers || {};
2854
2870
  if ("string" != typeof outgoing.headers.connection || !upgradeHeader.test(outgoing.headers.connection)) outgoing.headers.connection = "close";
2855
2871
  }
2872
+ outgoing.headers = outgoing.headers || {};
2873
+ forceConnectionCloseForTransferEncoding(outgoing.headers);
2856
2874
  const target = options[forward || "target"];
2857
2875
  const targetPath = target && false !== options.prependPath ? target.pathname || "" : "";
2858
2876
  const targetSearch = target instanceof URL && false !== options.prependPath ? target.search || "" : "";
@@ -2950,6 +2968,7 @@ const webOutgoingMiddleware = [
2950
2968
  defineProxyOutgoingMiddleware((req, res, proxyRes, options)=>{
2951
2969
  if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers.location && redirectRegex.test(String(proxyRes.statusCode))) {
2952
2970
  const target = _toURL(options.target);
2971
+ const keepProtocolRelative = proxyRes.headers.location.startsWith("//") && !options.protocolRewrite;
2953
2972
  const u = new URL(proxyRes.headers.location, target);
2954
2973
  if (target.host !== u.host) return;
2955
2974
  if (options.hostRewrite) u.host = options.hostRewrite;
@@ -2958,7 +2977,7 @@ const webOutgoingMiddleware = [
2958
2977
  else if (req.headers.host) u.host = req.headers.host;
2959
2978
  }
2960
2979
  if (options.protocolRewrite) u.protocol = options.protocolRewrite;
2961
- proxyRes.headers.location = u.toString();
2980
+ proxyRes.headers.location = keepProtocolRelative ? u.href.slice(u.protocol.length) : u.href;
2962
2981
  }
2963
2982
  }),
2964
2983
  defineProxyOutgoingMiddleware((req, res, proxyRes, options)=>{
@@ -3008,7 +3027,7 @@ const nativeAgents = {
3008
3027
  http: node_http,
3009
3028
  https: node_https
3010
3029
  };
3011
- const redirectStatuses = new Set([
3030
+ const redirectStatuses = /* @__PURE__ */ new Set([
3012
3031
  301,
3013
3032
  302,
3014
3033
  303,
@@ -3017,10 +3036,7 @@ const redirectStatuses = new Set([
3017
3036
  ]);
3018
3037
  const webIncomingMiddleware = [
3019
3038
  defineProxyMiddleware((req)=>{
3020
- if (("DELETE" === req.method || "OPTIONS" === req.method) && !req.headers["content-length"]) {
3021
- req.headers["content-length"] = "0";
3022
- delete req.headers["transfer-encoding"];
3023
- }
3039
+ if (("DELETE" === req.method || "OPTIONS" === req.method) && !req.headers["content-length"] && !req.headers["transfer-encoding"]) req.headers["content-length"] = "0";
3024
3040
  }),
3025
3041
  defineProxyMiddleware((req, res, options)=>{
3026
3042
  if (options.timeout) req.socket.setTimeout(options.timeout, ()=>{
@@ -3123,6 +3139,7 @@ const webIncomingMiddleware = [
3123
3139
  delete redirectHeaders["content-type"];
3124
3140
  delete redirectHeaders["transfer-encoding"];
3125
3141
  }
3142
+ forceConnectionCloseForTransferEncoding(redirectHeaders);
3126
3143
  const redirectOpts = {
3127
3144
  hostname: location.hostname,
3128
3145
  port: location.port || (isHTTPS ? 443 : 80),
@@ -3349,15 +3366,15 @@ function _createProxyFn(type, server) {
3349
3366
  for (const pass of server._getPasses(type)){
3350
3367
  let stop;
3351
3368
  try {
3352
- stop = pass(req, res, requestOptions, server, head, (error)=>{
3369
+ stop = pass(req, res, requestOptions, server, head, (error, _req, _res, url)=>{
3353
3370
  if (server.listenerCount("error") > 0) {
3354
- server.emit("error", error, req, res);
3371
+ server.emit("error", error, req, res, url);
3355
3372
  _resolve();
3356
3373
  } else _reject(error);
3357
3374
  });
3358
3375
  } catch (error) {
3359
3376
  if (server.listenerCount("error") > 0) {
3360
- server.emit("error", error, req, res);
3377
+ server.emit("error", error, req, res, requestOptions.target || requestOptions.forward);
3361
3378
  _resolve();
3362
3379
  } else _reject(error);
3363
3380
  break;
@@ -3370,29 +3387,41 @@ function _createProxyFn(type, server) {
3370
3387
  return callbackPromise;
3371
3388
  };
3372
3389
  }
3373
- new Set([
3374
- 301,
3375
- 302,
3376
- 303,
3377
- 307,
3378
- 308
3379
- ]);
3380
- var errors_ERRORS;
3381
- (function(ERRORS) {
3382
- ERRORS["ERR_CONFIG_FACTORY_TARGET_MISSING"] = "[HPM] Missing \"target\" option. Example: {target: \"http://www.example.org\"}";
3383
- ERRORS["ERR_CONTEXT_MATCHER_GENERIC"] = "[HPM] Invalid pathFilter. Expecting something like: \"/api\" or [\"/api\", \"/ajax\"]";
3384
- ERRORS["ERR_CONTEXT_MATCHER_INVALID_ARRAY"] = "[HPM] Invalid pathFilter. Plain paths (e.g. \"/api\") can not be mixed with globs (e.g. \"/api/**\"). Expecting something like: [\"/api\", \"/ajax\"] or [\"/api/**\", \"!**.html\"].";
3385
- ERRORS["ERR_PATH_REWRITER_CONFIG"] = "[HPM] Invalid pathRewrite config. Expecting object with pathRewrite config or a rewrite function";
3386
- })(errors_ERRORS || (errors_ERRORS = {}));
3390
+ class errors_HttpProxyMiddlewareError extends Error {
3391
+ code;
3392
+ constructor(message, code){
3393
+ super(message);
3394
+ this.code = code;
3395
+ this.name = this.constructor.name;
3396
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
3397
+ }
3398
+ }
3387
3399
  function verifyConfig(options) {
3388
- if (!options.target && !options.router) throw new Error(errors_ERRORS.ERR_CONFIG_FACTORY_TARGET_MISSING);
3400
+ if (!options.target && !options.router) throw new errors_HttpProxyMiddlewareError('[HPM] Missing "target" option. Example: {target: "http://www.example.org"}', 'ERR_CONFIG_FACTORY_TARGET_MISSING');
3389
3401
  }
3390
- const src = __webpack_require__("./node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/index.js");
3402
+ const src = __webpack_require__("./node_modules/.pnpm/debug@4.4.3_supports-color@8.1.1/node_modules/debug/src/index.js");
3391
3403
  const Debug = src('http-proxy-middleware');
3404
+ function definePlugin(fn) {
3405
+ return fn;
3406
+ }
3392
3407
  const debug = Debug.extend('debug-proxy-errors-plugin');
3393
- const debugProxyErrorsPlugin = (proxyServer)=>{
3408
+ const BODY_PARSER_ERROR_MESSAGE = `[HPM] Connection reset (ECONNRESET) detected with non-empty "req.body" [ERR_HPM.GH40].
3409
+
3410
+ This usually means that the POST request body (req.body) was already parsed before reaching the proxy.
3411
+ When bodyParser runs first, it consumes the request stream, leaving the proxy unable to forward the body data to the target server.
3412
+
3413
+ How to fix this issue:
3414
+ - Option 1: Place the proxy middleware before the bodyParser middleware.
3415
+ - Option 2: Use 'fixRequestBody()' helper to fix this issue.
3416
+
3417
+ For more details, see: https://github.com/chimurai/http-proxy-middleware/issues/40\n`;
3418
+ function hasParsedBody(req) {
3419
+ return Boolean(req && 'POST' === req.method && 'body' in req && req.body);
3420
+ }
3421
+ const debugProxyErrorsPlugin = definePlugin((proxyServer, options)=>{
3394
3422
  proxyServer.on('error', (error, req, res, target)=>{
3395
3423
  debug(`httpxy error event: \n%O`, error);
3424
+ if ('ECONNRESET' === error.code && hasParsedBody(req)) console.error(styleText('red', BODY_PARSER_ERROR_MESSAGE));
3396
3425
  });
3397
3426
  proxyServer.on('proxyReq', (proxyReq, req, socket)=>{
3398
3427
  socket.on('error', (error)=>{
@@ -3425,11 +3454,18 @@ const debugProxyErrorsPlugin = (proxyServer)=>{
3425
3454
  proxyServer.on('econnreset', (error, req, res, target)=>{
3426
3455
  debug(`httpxy econnreset event: \n%O`, error);
3427
3456
  });
3428
- };
3457
+ });
3429
3458
  function getStatusCode(errorCode) {
3430
3459
  let statusCode;
3431
- if (/HPE_INVALID/.test(errorCode)) statusCode = 502;
3432
- else switch(errorCode){
3460
+ if (/HPE_INVALID/.test(errorCode)) {
3461
+ statusCode = 502;
3462
+ return statusCode;
3463
+ }
3464
+ if (/HPM_ERR_INVALID_MULTIPART_/.test(errorCode)) {
3465
+ statusCode = 400;
3466
+ return statusCode;
3467
+ }
3468
+ switch(errorCode){
3433
3469
  case 'ECONNRESET':
3434
3470
  case 'ENOTFOUND':
3435
3471
  case 'ECONNREFUSED':
@@ -3451,7 +3487,7 @@ function isResponseLike(obj) {
3451
3487
  function isSocketLike(obj) {
3452
3488
  return obj && 'function' == typeof obj.write && !('writeHead' in obj);
3453
3489
  }
3454
- const errorResponsePlugin = (proxyServer, options)=>{
3490
+ const errorResponsePlugin = definePlugin((proxyServer, options)=>{
3455
3491
  proxyServer.on('error', (err, req, res, target)=>{
3456
3492
  if (!req || !res) throw err;
3457
3493
  if (isResponseLike(res)) {
@@ -3463,7 +3499,7 @@ const errorResponsePlugin = (proxyServer, options)=>{
3463
3499
  res.end(`Error occurred while trying to proxy: ${sanitize(host)}${sanitize(req.url)}`);
3464
3500
  } else if (isSocketLike(res)) res.destroy();
3465
3501
  });
3466
- };
3502
+ });
3467
3503
  const noopLogger = {
3468
3504
  info: ()=>{},
3469
3505
  warn: ()=>{},
@@ -3483,7 +3519,7 @@ function createUrl({ protocol, host, port, path }) {
3483
3519
  function logger_plugin_getPort(sockets) {
3484
3520
  return Object.keys(sockets || {})?.[0]?.split(':')[1];
3485
3521
  }
3486
- const loggerPlugin = (proxyServer, options)=>{
3522
+ const loggerPlugin = definePlugin((proxyServer, options)=>{
3487
3523
  const logger = getLogger(options);
3488
3524
  proxyServer.on('error', (err, req, res, target)=>{
3489
3525
  const hostname = req?.headers?.host;
@@ -3520,12 +3556,12 @@ const loggerPlugin = (proxyServer, options)=>{
3520
3556
  proxyServer.on('close', (req, proxySocket, proxyHead)=>{
3521
3557
  logger.info('[HPM] Client disconnected: %o', proxySocket.address());
3522
3558
  });
3523
- };
3559
+ });
3524
3560
  function function_getFunctionName(fn) {
3525
3561
  return fn.name || '[anonymous Function]';
3526
3562
  }
3527
3563
  const proxy_events_debug = Debug.extend('proxy-events-plugin');
3528
- const proxyEventsPlugin = (proxyServer, options)=>{
3564
+ const proxyEventsPlugin = definePlugin((proxyServer, options)=>{
3529
3565
  if (!options.on) return;
3530
3566
  let eventName;
3531
3567
  for(eventName in options.on)if (Object.prototype.hasOwnProperty.call(options.on, eventName)) {
@@ -3534,7 +3570,7 @@ const proxyEventsPlugin = (proxyServer, options)=>{
3534
3570
  proxy_events_debug(`register event handler: "${eventName}" -> "${function_getFunctionName(handler)}"`);
3535
3571
  proxyServer.on(eventName, handler);
3536
3572
  }
3537
- };
3573
+ });
3538
3574
  function getPlugins(options) {
3539
3575
  const maybeErrorResponsePlugin = options.on?.error ? [] : [
3540
3576
  errorResponsePlugin
@@ -3559,13 +3595,13 @@ function matchPathFilter(pathFilter = '/', uri, req) {
3559
3595
  if (Array.isArray(pathFilter)) {
3560
3596
  if (pathFilter.every(isStringPath)) return matchMultiPath(pathFilter, uri);
3561
3597
  if (pathFilter.every(isGlobPath)) return matchMultiGlobPath(pathFilter, uri);
3562
- throw new Error(errors_ERRORS.ERR_CONTEXT_MATCHER_INVALID_ARRAY);
3598
+ throw new errors_HttpProxyMiddlewareError('[HPM] Invalid pathFilter. Plain paths (e.g. "/api") can not be mixed with globs (e.g. "/api/**"). Expecting something like: ["/api", "/ajax"] or ["/api/**", "!**.html"].', 'HPM_INVALID_PATH_FILTER_ARRAY_CONFIG');
3563
3599
  }
3564
3600
  if ('function' == typeof pathFilter) {
3565
3601
  const pathname = getUrlPathName(uri);
3566
- return pathFilter(pathname, req);
3602
+ return Boolean(pathFilter(pathname, req));
3567
3603
  }
3568
- throw new Error(errors_ERRORS.ERR_CONTEXT_MATCHER_GENERIC);
3604
+ throw new errors_HttpProxyMiddlewareError('[HPM] Invalid pathFilter. Expecting something like: "/api" or ["/api", "/ajax"]', 'HPM_INVALID_PATH_FILTER_CONFIG');
3569
3605
  }
3570
3606
  function matchSingleStringPath(pathFilter, uri) {
3571
3607
  const pathname = getUrlPathName(uri);
@@ -3627,7 +3663,7 @@ function isValidRewriteConfig(rewriteConfig) {
3627
3663
  if ('function' == typeof rewriteConfig) return true;
3628
3664
  if (isPlainObject(rewriteConfig)) return 0 !== Object.keys(rewriteConfig).length;
3629
3665
  if (null == rewriteConfig) return false;
3630
- throw new Error(errors_ERRORS.ERR_PATH_REWRITER_CONFIG);
3666
+ throw new errors_HttpProxyMiddlewareError('[HPM] Invalid pathRewrite config. Expecting object with pathRewrite config or a rewrite function', 'HPM_INVALID_PATH_REWRITER_CONFIG');
3631
3667
  }
3632
3668
  function parsePathRewriteRules(rewriteConfig) {
3633
3669
  const rules = [];
@@ -3641,20 +3677,26 @@ function parsePathRewriteRules(rewriteConfig) {
3641
3677
  return rules;
3642
3678
  }
3643
3679
  const router_debug = Debug.extend('router');
3644
- async function getTarget(req, config) {
3680
+ async function getTarget(req, res, config) {
3645
3681
  let newTarget;
3646
3682
  const router = config.router;
3647
3683
  if (isPlainObject(router)) newTarget = getTargetFromProxyTable(req, router);
3648
- else if ('function' == typeof router) newTarget = await router(req);
3684
+ else if ('function' == typeof router) newTarget = await router(req, res, config);
3649
3685
  return newTarget;
3650
3686
  }
3651
3687
  function getTargetFromProxyTable(req, table) {
3652
3688
  let result;
3653
3689
  const host = req.headers.host ?? '';
3654
3690
  const path = req.url ?? '';
3655
- const hostAndPath = host + path;
3656
3691
  for (const [key, value] of Object.entries(table))if (containsPath(key)) {
3657
- if (hostAndPath.indexOf(key) > -1) {
3692
+ if (isHostAndPathKey(key)) {
3693
+ const [keyHost, keyPath] = splitHostAndPathKey(key);
3694
+ if (host === keyHost && path.startsWith(keyPath)) {
3695
+ result = value;
3696
+ router_debug('match: "%s" -> "%s"', key, result);
3697
+ break;
3698
+ }
3699
+ } else if (path.startsWith(key)) {
3658
3700
  result = value;
3659
3701
  router_debug('match: "%s" -> "%s"', key, result);
3660
3702
  break;
@@ -3669,6 +3711,16 @@ function getTargetFromProxyTable(req, table) {
3669
3711
  function containsPath(v) {
3670
3712
  return v.indexOf('/') > -1;
3671
3713
  }
3714
+ function isHostAndPathKey(v) {
3715
+ return containsPath(v) && !v.startsWith('/');
3716
+ }
3717
+ function splitHostAndPathKey(v) {
3718
+ const firstSlash = v.indexOf('/');
3719
+ return [
3720
+ v.slice(0, firstSlash),
3721
+ v.slice(firstSlash)
3722
+ ];
3723
+ }
3672
3724
  const ipv6_debug = Debug.extend('ipv6');
3673
3725
  function normalizeIPv6LiteralTargets(options) {
3674
3726
  options.target = normalizeIPv6ProxyTarget(options.target, 'target');
@@ -3677,9 +3729,12 @@ function normalizeIPv6LiteralTargets(options) {
3677
3729
  function normalizeIPv6ProxyTarget(target, optionName) {
3678
3730
  const targetUrl = toTargetUrl(target);
3679
3731
  if (targetUrl && isBracketedIPv6Hostname(targetUrl.hostname)) {
3732
+ const normalizedHostname = normalizeIPv6DestinationHostname(stripBrackets(targetUrl.hostname));
3680
3733
  ipv6_debug('normalized IPv6 "%s" %s', optionName, target);
3734
+ const auth = targetUrl.username || targetUrl.password ? `${targetUrl.username}:${targetUrl.password}` : void 0;
3681
3735
  return {
3682
- hostname: stripBrackets(targetUrl.hostname),
3736
+ hostname: normalizedHostname,
3737
+ auth,
3683
3738
  pathname: targetUrl.pathname,
3684
3739
  port: targetUrl.port,
3685
3740
  protocol: targetUrl.protocol,
@@ -3698,9 +3753,16 @@ function isBracketedIPv6Hostname(hostname) {
3698
3753
  function stripBrackets(hostname) {
3699
3754
  return hostname.replace(/^\[|\]$/g, '');
3700
3755
  }
3756
+ function normalizeIPv6DestinationHostname(hostname) {
3757
+ if ('::' === hostname) {
3758
+ ipv6_debug('normalizing hostname unspecified IPv6 address (::) to loopback (::1)');
3759
+ return '::1';
3760
+ }
3761
+ return hostname;
3762
+ }
3701
3763
  class HttpProxyMiddleware {
3702
- wsInternalSubscribed = false;
3703
- serverOnCloseSubscribed = false;
3764
+ wsInternalSubscribedServers = new WeakSet();
3765
+ activeServers = new Set();
3704
3766
  proxyOptions;
3705
3767
  proxy;
3706
3768
  pathRewriter;
@@ -3714,14 +3776,18 @@ class HttpProxyMiddleware {
3714
3776
  this.registerPlugins(this.proxy, this.proxyOptions);
3715
3777
  this.pathRewriter = createPathRewriter(this.proxyOptions.pathRewrite);
3716
3778
  this.middleware.upgrade = (req, socket, head)=>{
3717
- if (!this.wsInternalSubscribed) this.handleUpgrade(req, socket, head);
3779
+ const server = this.#getServer(req);
3780
+ if (server && !this.wsInternalSubscribedServers.has(server)) this.handleUpgrade(req, socket, head);
3718
3781
  };
3719
3782
  }
3783
+ #getServer(req) {
3784
+ return req.socket?.server;
3785
+ }
3720
3786
  middleware = async (req, res, next)=>{
3721
3787
  if (this.shouldProxy(this.proxyOptions.pathFilter, req)) {
3722
3788
  let activeProxyOptions;
3723
3789
  try {
3724
- activeProxyOptions = await this.prepareProxyRequest(req);
3790
+ activeProxyOptions = await this.prepareProxyRequest(req, res);
3725
3791
  if (!activeProxyOptions.target && !activeProxyOptions.forward) throw new Error('Must provide a proper URL as target');
3726
3792
  } catch (err) {
3727
3793
  next?.(err);
@@ -3735,15 +3801,17 @@ class HttpProxyMiddleware {
3735
3801
  next?.(err);
3736
3802
  }
3737
3803
  } else next?.();
3738
- const server = req.socket?.server;
3739
- if (server && !this.serverOnCloseSubscribed) {
3804
+ const server = this.#getServer(req);
3805
+ if (server && !this.activeServers.has(server)) {
3806
+ Debug('registering server close listener');
3807
+ this.activeServers.add(server);
3740
3808
  server.on('close', ()=>{
3741
- Debug('server close signal received: closing proxy server');
3742
- this.proxy.close(()=>{
3743
- Debug('proxy server closed');
3744
- });
3809
+ Debug('server close signal received.');
3810
+ this.activeServers.delete(server);
3811
+ if (this.activeServers.size > 0) return void Debug(`proxy server not closed: ${this.activeServers.size} server(s) still active`);
3812
+ Debug('closing proxy server');
3813
+ this.proxy.close(()=>Debug('proxy server closed'));
3745
3814
  });
3746
- this.serverOnCloseSubscribed = true;
3747
3815
  }
3748
3816
  if (true === this.proxyOptions.ws && server) this.catchUpgradeRequest(server);
3749
3817
  };
@@ -3755,18 +3823,17 @@ class HttpProxyMiddleware {
3755
3823
  });
3756
3824
  }
3757
3825
  catchUpgradeRequest = (server)=>{
3758
- if (!this.wsInternalSubscribed) {
3826
+ if (!this.wsInternalSubscribedServers.has(server)) {
3759
3827
  Debug('subscribing to server upgrade event');
3760
3828
  server.on('upgrade', this.handleUpgrade);
3761
- this.wsInternalSubscribed = true;
3829
+ this.wsInternalSubscribedServers.add(server);
3762
3830
  }
3763
3831
  };
3764
3832
  handleUpgrade = async (req, socket, head)=>{
3765
3833
  try {
3766
3834
  if (this.shouldProxy(this.proxyOptions.pathFilter, req)) {
3767
- const proxiedReq = req;
3768
- const activeProxyOptions = await this.prepareProxyRequest(proxiedReq);
3769
- await this.proxy.ws(proxiedReq, socket, activeProxyOptions, head);
3835
+ const activeProxyOptions = await this.prepareProxyRequest(req, void 0);
3836
+ await this.proxy.ws(req, socket, activeProxyOptions, head);
3770
3837
  Debug('server upgrade event received. Proxying WebSocket');
3771
3838
  }
3772
3839
  } catch (err) {
@@ -3782,26 +3849,26 @@ class HttpProxyMiddleware {
3782
3849
  return false;
3783
3850
  }
3784
3851
  };
3785
- prepareProxyRequest = async (req)=>{
3852
+ prepareProxyRequest = async (req, res)=>{
3786
3853
  const newProxyOptions = Object.assign({}, this.proxyOptions);
3787
- await this.applyRouter(req, newProxyOptions);
3854
+ await this.applyRouter(req, res, newProxyOptions);
3788
3855
  normalizeIPv6LiteralTargets(newProxyOptions);
3789
- await this.applyPathRewrite(req, this.pathRewriter);
3856
+ await this.applyPathRewrite(req, res, this.pathRewriter, newProxyOptions);
3790
3857
  return newProxyOptions;
3791
3858
  };
3792
- applyRouter = async (req, options)=>{
3859
+ applyRouter = async (req, res, options)=>{
3793
3860
  let newTarget;
3794
3861
  if (options.router) {
3795
- newTarget = await getTarget(req, options);
3862
+ newTarget = await getTarget(req, res, options);
3796
3863
  if (newTarget) {
3797
3864
  Debug('router new target: "%s"', newTarget);
3798
3865
  options.target = newTarget;
3799
3866
  }
3800
3867
  }
3801
3868
  };
3802
- applyPathRewrite = async (req, pathRewriter)=>{
3869
+ applyPathRewrite = async (req, res, pathRewriter, options)=>{
3803
3870
  if (req.url && pathRewriter) {
3804
- const path = await pathRewriter(req.url, req);
3871
+ const path = await pathRewriter(req.url, req, res, options);
3805
3872
  if ('string' == typeof path) {
3806
3873
  Debug('pathRewrite new path: %s', path);
3807
3874
  req.url = path;