whistle 2.9.109 → 2.10.1

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 (41) hide show
  1. package/assets/js/log.js +8 -4
  2. package/bin/util.js +1 -1
  3. package/biz/index.js +12 -10
  4. package/biz/webui/cgi-bin/certs/active.js +6 -0
  5. package/biz/webui/cgi-bin/certs/remove.js +0 -1
  6. package/biz/webui/cgi-bin/certs/upload.js +0 -1
  7. package/biz/webui/cgi-bin/util.js +7 -20
  8. package/biz/webui/htdocs/index.html +1 -1
  9. package/biz/webui/htdocs/js/index.js +43 -43
  10. package/biz/webui/lib/index.js +10 -13
  11. package/lib/config.js +17 -36
  12. package/lib/handlers/file-proxy.js +2 -1
  13. package/lib/handlers/http-proxy.js +1 -1
  14. package/lib/https/ca.js +34 -27
  15. package/lib/https/h2.js +1 -1
  16. package/lib/https/index.js +21 -17
  17. package/lib/index.js +1 -1
  18. package/lib/init.js +13 -12
  19. package/lib/inspectors/req.js +13 -10
  20. package/lib/inspectors/res.js +375 -390
  21. package/lib/inspectors/rules.js +11 -0
  22. package/lib/plugins/compat.js +108 -0
  23. package/lib/plugins/get-plugins-sync.js +1 -4
  24. package/lib/plugins/index.js +92 -284
  25. package/lib/plugins/load-plugin.js +205 -223
  26. package/lib/plugins/module-paths.js +3 -4
  27. package/lib/plugins/proxy.js +4 -7
  28. package/lib/rules/index.js +69 -66
  29. package/lib/rules/protocols.js +6 -0
  30. package/lib/rules/rules.js +44 -32
  31. package/lib/rules/util.js +30 -0
  32. package/lib/service/composer.js +5 -5
  33. package/lib/service/util.js +7 -21
  34. package/lib/tunnel.js +15 -12
  35. package/lib/upgrade.js +9 -10
  36. package/lib/util/common.js +171 -48
  37. package/lib/util/file-mgr.js +3 -7
  38. package/lib/util/index.js +101 -143
  39. package/package.json +1 -1
  40. package/README-en_US.md +0 -80
  41. package/biz/webui/htdocs/img/assistant.svg +0 -1
@@ -29,6 +29,7 @@ var LIKE_JSON_RE = /^\s*[\{\[]/;
29
29
  var NO_STORE_RE = /^no-store$/i;
30
30
  var NO_CACHE_RE = /^(?:no|no-cache|no-store)$/i;
31
31
  var X_RE = /^x/;
32
+ var clientIpKey = config.CLIENT_IP_HEADER;
32
33
  var BODY_PROTOCOLS = [
33
34
  'attachment',
34
35
  'resReplace',
@@ -218,15 +219,10 @@ module.exports = function (req, res, next) {
218
219
  ? util.rule.getMatcher(proxyRule)
219
220
  : null;
220
221
  var headers = req.headers;
221
- var curUrl,
222
- auth,
223
- isInternalProxy,
224
- isHttpsProxy,
225
- origPath,
226
- origProxy;
222
+ var auth, isInternalProxy, isHttpsProxy, origPath, origProxy;
227
223
  if (!hostIp) {
228
- if (options.localDNS && net.isIP(options.host)) {
229
- curUrl = options.host;
224
+ if (options.localDNS) {
225
+ req.curUrl = '';
230
226
  } else if (proxyUrl) {
231
227
  isHttpsProxy = proxyRule.isHttps;
232
228
  isInternalProxy = proxyRule.isInternal || util.isInternalProxy(req);
@@ -240,84 +236,73 @@ module.exports = function (req, res, next) {
240
236
  } else if (proxyRule.isHttp2https) {
241
237
  options.protocol = 'https:';
242
238
  }
243
- curUrl = 'http:' + util.removeProtocol(proxyUrl);
239
+ req.curUrl = 'http:' + util.removeProtocol(proxyUrl);
244
240
  } else {
245
- curUrl = options.href;
241
+ req.curUrl = options.href;
246
242
  }
247
243
  }
248
- req.curUrl = curUrl;
249
- req.setServerPort =
250
- req.setServerPort ||
251
- function (serverPort) {
252
- req.serverPort = serverPort;
244
+ if (!req.setServerPort) {
245
+ req.setServerPort = function (port) {
246
+ req.serverPort = port;
253
247
  };
254
- rules.resolveHost(
255
- req,
256
- function (err, ip, port, hostRule) {
257
- var setHostsInfo = function (_ip, _port, _host, withPort) {
258
- ip = _ip || '127.0.0.1';
259
- port = _port;
260
- req.dnsTime = Date.now() - now;
261
- req.hostIp = util.joinIpPort(_ip, withPort && _port);
262
- if (_host) {
263
- resRules.host = _host;
264
- }
265
- };
266
- if (proxyUrl && proxyRule && hostRule) {
267
- proxyRule.host = hostRule;
268
- hostRule = null;
248
+ }
249
+ rules.resolveHost(req, function (err, ip, port, hostRule) {
250
+ var setHostsInfo = function (_ip, _port, _host, withPort) {
251
+ ip = _ip || '127.0.0.1';
252
+ port = _port;
253
+ req.dnsTime = Date.now() - now;
254
+ req.hostIp = util.joinIpPort(_ip, withPort && _port);
255
+ if (_host) {
256
+ resRules.host = _host;
269
257
  }
270
- setHostsInfo(hostIp || ip, hostPort || port, hostRule);
271
- if (err) {
272
- showDnsError(res, err);
273
- return;
258
+ };
259
+ if (proxyUrl && proxyRule && hostRule) {
260
+ proxyRule.host = hostRule;
261
+ hostRule = null;
262
+ }
263
+ setHostsInfo(hostIp || ip, hostPort || port, hostRule);
264
+ if (err) {
265
+ showDnsError(res, err);
266
+ return;
267
+ }
268
+ if (req.disable.keepalive) {
269
+ req.disable.keepAlive = true;
270
+ }
271
+ var isHttps = options.protocol == 'https:';
272
+ var proxyOptions, isProxyPort, isSocks;
273
+ var setAgent = function (disable) {
274
+ if (disable || req.disable.keepAlive || (isHttps && cert)) {
275
+ options.agent = false;
276
+ } else {
277
+ options.agent = isHttps ? config.httpsAgent : config.httpAgent;
274
278
  }
275
- if (req.disable.keepalive) {
276
- req.disable.keepAlive = true;
279
+ };
280
+ checkH2(req, isHttps);
281
+ if (proxyUrl) {
282
+ proxyOptions = parseUrl(proxyUrl);
283
+ proxyOptions.host = ip;
284
+ proxyOptions.auth = proxyOptions.auth || req._pacAuth;
285
+ isSocks = proxyRule.isSocks;
286
+ var proxyPort = proxyOptions.port;
287
+ if (!proxyPort) {
288
+ proxyPort = proxyOptions.port = isSocks ? 1080 : isHttpsProxy ? 443 : 80;
277
289
  }
278
- var isHttps = options.protocol == 'https:';
279
- var proxyOptions, isProxyPort, isSocks;
280
- var setAgent = function (disable) {
281
- if (disable || req.disable.keepAlive || (isHttps && cert)) {
282
- options.agent = false;
283
- } else {
284
- options.agent = isHttps
285
- ? config.httpsAgent
286
- : config.httpAgent;
287
- }
288
- };
289
- checkH2(req, isHttps);
290
- if (proxyUrl) {
291
- proxyOptions = parseUrl(proxyUrl);
292
- proxyOptions.host = ip;
293
- proxyOptions.auth = proxyOptions.auth || req._pacAuth;
294
- isSocks = proxyRule.isSocks;
295
- var proxyPort = proxyOptions.port;
296
- if (!proxyPort) {
297
- proxyPort = proxyOptions.port = isSocks
298
- ? 1080
299
- : isHttpsProxy
300
- ? 443
301
- : 80;
302
- }
303
- if (proxyOptions.auth) {
304
- auth =
305
- 'Basic ' +
306
- util.toBuffer(proxyOptions.auth + '').toString('base64');
307
- } else {
308
- auth = headers['proxy-authorization'];
309
- }
310
- if (
290
+ if (proxyOptions.auth) {
291
+ auth = 'Basic ' + util.toBuffer(proxyOptions.auth + '').toString('base64');
292
+ } else {
293
+ auth = headers['proxy-authorization'];
294
+ }
295
+ if (
311
296
  isHttps ||
312
297
  (req.useH2 && !isInternalProxy) ||
313
298
  isSocks ||
314
299
  isHttpsProxy ||
315
300
  req._phost
316
301
  ) {
317
- isProxyPort = util.isProxyPort(proxyPort);
318
- if (isProxyPort && util.isLocalAddress(ip)) {
319
- req.setServerPort(config.port);
320
- res.response(
302
+ isProxyPort = util.isProxyPort(proxyPort);
303
+ if (isProxyPort && util.isLocalAddress(ip)) {
304
+ req.setServerPort(config.port);
305
+ res.response(
321
306
  util.wrapResponse({
322
307
  statusCode: 302,
323
308
  headers: {
@@ -328,105 +313,105 @@ module.exports = function (req, res, next) {
328
313
  }
329
314
  })
330
315
  );
331
- } else {
332
- var curServerPort = options.port || (isHttps ? 443 : 80);
333
- var proxyHeaders = {
334
- host: util.joinIpPort(options.hostname, curServerPort),
335
- 'proxy-connection': req.disable.proxyConnection
316
+ } else {
317
+ var curServerPort = options.port || (isHttps ? 443 : 80);
318
+ var proxyHeaders = {
319
+ host: util.joinIpPort(options.hostname, curServerPort),
320
+ 'proxy-connection': req.disable.proxyConnection
336
321
  ? 'close'
337
322
  : 'keep-alive'
338
- };
339
- pluginMgr.getTunnelKeys().forEach(function (k) {
340
- var val = headers[k];
341
- if (val) {
342
- proxyHeaders[k] = val;
343
- }
344
- });
345
- if (auth) {
346
- proxyHeaders['proxy-authorization'] = auth;
347
- }
348
- if (req.disable.proxyUA) {
349
- delete proxyHeaders['user-agent'];
350
- } else if (headers['user-agent']) {
351
- proxyHeaders['user-agent'] = headers['user-agent'];
352
- }
353
- if (!util.isLocalAddress(req.clientIp)) {
354
- proxyHeaders[config.CLIENT_IP_HEAD] = req.clientIp;
355
- }
356
- if (isHttps || req.useH2) {
357
- util.checkIfAddInterceptPolicy(proxyHeaders, headers);
358
- }
359
- if (isProxyPort) {
360
- proxyHeaders[config.WEBUI_HEAD] = 1;
361
- }
362
- if (util.isProxyPort(curServerPort) || util.isLocalPHost(req, isHttps)) {
363
- headers[config.WEBUI_HEAD] = 1;
364
- }
365
- var clientId = req.headers[config.CLIENT_ID_HEADER];
366
- if (clientId) {
367
- proxyHeaders[config.CLIENT_ID_HEADER] = clientId;
323
+ };
324
+ pluginMgr.getTunnelKeys().forEach(function (k) {
325
+ var val = headers[k];
326
+ if (val) {
327
+ proxyHeaders[k] = val;
368
328
  }
369
- util.setClientId(
329
+ });
330
+ if (auth) {
331
+ proxyHeaders['proxy-authorization'] = auth;
332
+ }
333
+ if (req.disable.proxyUA) {
334
+ delete proxyHeaders['user-agent'];
335
+ } else if (headers['user-agent']) {
336
+ proxyHeaders['user-agent'] = headers['user-agent'];
337
+ }
338
+ if (!util.isLocalAddress(req.clientIp)) {
339
+ proxyHeaders[clientIpKey] = req.clientIp;
340
+ }
341
+ if (isHttps || req.useH2) {
342
+ util.checkIfAddInterceptPolicy(proxyHeaders, headers);
343
+ }
344
+ if (isProxyPort) {
345
+ proxyHeaders[config.WEBUI_HEAD] = 1;
346
+ }
347
+ if (util.isProxyPort(curServerPort) || util.isLocalPHost(req, isHttps)) {
348
+ headers[config.WEBUI_HEAD] = 1;
349
+ }
350
+ var clientId = req.headers[config.CLIENT_ID_HEADER];
351
+ if (clientId) {
352
+ proxyHeaders[config.CLIENT_ID_HEADER] = clientId;
353
+ }
354
+ util.setClientId(
370
355
  proxyHeaders,
371
356
  req.enable,
372
357
  req.disable,
373
358
  req.clientIp,
374
359
  isInternalProxy
375
360
  );
376
- var phost = req._phost;
377
- var opts = {
378
- isSocks: isSocks,
379
- isHttps: isHttps,
380
- _phost: phost,
381
- proxyServername: isHttpsProxy
361
+ var phost = req._phost;
362
+ var opts = {
363
+ isSocks: isSocks,
364
+ isHttps: isHttps,
365
+ _phost: phost,
366
+ proxyServername: isHttpsProxy
382
367
  ? proxyOptions.hostname
383
368
  : null,
384
- proxyHost: ip,
385
- clientIp: proxyHeaders[config.CLIENT_IP_HEAD],
386
- proxyPort: proxyPort,
387
- url: options.href,
388
- auth: proxyOptions.auth,
389
- headers: proxyHeaders
390
- };
391
- if (phost) {
392
- options.host = phost.hostname;
393
- if (phost.port > 0) {
394
- options.port = phost.port;
395
- } else if (!options.port) {
396
- options.port = isHttps ? 443 : 80;
397
- }
398
- proxyHeaders.host = util.joinIpPort(options.host, options.port);
399
- } else {
400
- options.host = options.hostname;
369
+ proxyHost: ip,
370
+ clientIp: proxyHeaders[clientIpKey],
371
+ proxyPort: proxyPort,
372
+ url: options.href,
373
+ auth: proxyOptions.auth,
374
+ headers: proxyHeaders
375
+ };
376
+ if (phost) {
377
+ options.host = phost.hostname;
378
+ if (phost.port > 0) {
379
+ options.port = phost.port;
380
+ } else if (!options.port) {
381
+ options.port = isHttps ? 443 : 80;
401
382
  }
402
- options._proxyOptions = opts;
403
- opts.proxyType = isSocks
383
+ proxyHeaders.host = util.joinIpPort(options.host, options.port);
384
+ } else {
385
+ options.host = options.hostname;
386
+ }
387
+ options._proxyOptions = opts;
388
+ opts.proxyType = isSocks
404
389
  ? 'socks'
405
390
  : isHttpsProxy
406
391
  ? 'https'
407
392
  : 'http';
408
- options._proxyPort = opts.proxyPort;
409
- origProxy = opts;
410
- request(options);
411
- }
412
- return;
393
+ options._proxyPort = opts.proxyPort;
394
+ origProxy = opts;
395
+ request(options);
413
396
  }
397
+ return;
398
+ }
414
399
 
415
- if (auth) {
416
- headers['proxy-authorization'] = auth;
417
- }
400
+ if (auth) {
401
+ headers['proxy-authorization'] = auth;
418
402
  }
403
+ }
419
404
 
420
- req.hostIp = util.joinIpPort(ip, port);
421
- port = proxyOptions ? proxyOptions.port : port || options.port;
422
- options.host = ip; //设置ip
423
- var curPort = port || (isHttps ? 443 : 80);
424
- isProxyPort = util.isProxyPort(curPort);
425
- var isLocalAddress = util.isLocalAddress(options.host);
426
- if (isProxyPort && isLocalAddress) {
427
- var redirectHost = config.customLocalUIHost || ip;
428
- var redirectPort = config.realPort || config.port;
429
- res.response(
405
+ req.hostIp = util.joinIpPort(ip, port);
406
+ port = proxyOptions ? proxyOptions.port : port || options.port;
407
+ options.host = ip; //设置ip
408
+ var curPort = port || (isHttps ? 443 : 80);
409
+ isProxyPort = util.isProxyPort(curPort);
410
+ var isLocalAddress = util.isLocalAddress(options.host);
411
+ if (isProxyPort && isLocalAddress) {
412
+ var redirectHost = config.customLocalUIHost || ip;
413
+ var redirectPort = config.realPort || config.port;
414
+ res.response(
430
415
  util.wrapResponse({
431
416
  statusCode: 302,
432
417
  headers: {
@@ -437,137 +422,137 @@ module.exports = function (req, res, next) {
437
422
  }
438
423
  })
439
424
  );
440
- } else {
441
- if (
425
+ } else {
426
+ if (
442
427
  isProxyPort ||
443
428
  util.isProxyPort(options.port || (isHttps ? 443 : 80)) ||
444
429
  util.isLocalPHost(req, isHttps)
445
430
  ) {
446
- headers[config.WEBUI_HEAD] = 1;
447
- }
448
- setAgent(isLocalAddress);
449
- request(options, port, true);
431
+ headers[config.WEBUI_HEAD] = 1;
450
432
  }
451
- function request(options, serverPort, direct) {
452
- options.headers = headers;
453
- options.method = req.method;
454
- util.setRejectUnauthorized(req, options);
455
- if (
433
+ setAgent(isLocalAddress);
434
+ request(options, port, true);
435
+ }
436
+ function request(options, serverPort, direct) {
437
+ options.headers = headers;
438
+ options.method = req.method;
439
+ util.setRejectUnauthorized(req, options);
440
+ if (
456
441
  !options.isPlugin &&
457
442
  !req._customHost &&
458
443
  (req.fullUrl !== req.realUrl || !headers.host)
459
444
  ) {
460
- headers.host = originHost;
461
- }
462
- if (req.disable.keepAlive) {
463
- headers.connection = 'close';
464
- }
465
- if (direct) {
466
- options.port = serverPort;
467
- if (proxyUrl) {
468
- origPath = options.path || '';
469
- }
445
+ headers.host = originHost;
446
+ }
447
+ if (req.disable.keepAlive) {
448
+ headers.connection = 'close';
449
+ }
450
+ if (direct) {
451
+ options.port = serverPort;
452
+ if (proxyUrl) {
453
+ origPath = options.path || '';
470
454
  }
455
+ }
471
456
 
472
- delete options.hostname; //防止自动dns
473
- delete options.protocol;
474
- if (isHttps && !req.disable.servername) {
475
- options.servername = util.parseHost(headers.host)[0];
476
- }
477
- var piped;
478
- var maxRetryCount = 1;
479
- var retryCount = 0;
480
- var retryXHost = 0;
481
- var resetCount = 0;
482
- var curClient, timer, newIp;
483
- var setProxyAgent = function (options, proxyOpts) {
484
- proxyOpts.cacheKey = options.cacheKey;
485
- proxyOpts.proxyTunnelPath = util.getProxyTunnelPath(
457
+ delete options.hostname; //防止自动dns
458
+ delete options.protocol;
459
+ if (isHttps && !req.disable.servername) {
460
+ options.servername = util.parseHost(headers.host)[0];
461
+ }
462
+ var piped;
463
+ var maxRetryCount = 1;
464
+ var retryCount = 0;
465
+ var retryXHost = 0;
466
+ var resetCount = 0;
467
+ var curClient, timer, newIp;
468
+ var setProxyAgent = function (options, proxyOpts) {
469
+ proxyOpts.cacheKey = options.cacheKey;
470
+ proxyOpts.proxyTunnelPath = util.getProxyTunnelPath(
486
471
  req,
487
472
  isHttps
488
473
  );
489
- proxyOpts.enableIntercept = true;
490
- options.agent = proxyOpts.isSocks
474
+ proxyOpts.enableIntercept = true;
475
+ options.agent = proxyOpts.isSocks
491
476
  ? config.getSocksAgent(proxyOpts)
492
477
  : config.getHttpsAgent(proxyOpts, options);
493
- };
494
- var retry = function (err) {
495
- clearTimeout(timer);
496
- timer = null;
497
- if (curClient) {
498
- curClient.removeListener('error', retry);
499
- curClient.removeListener('close', retry);
500
- curClient.on('error', util.noop);
501
- curClient.destroy();
502
- curClient = null;
503
- }
504
- if (req._hasError || req._hasRespond) {
505
- return;
506
- }
507
- if (err) {
478
+ };
479
+ var retry = function (err) {
480
+ clearTimeout(timer);
481
+ timer = null;
482
+ if (curClient) {
483
+ curClient.removeListener('error', retry);
484
+ curClient.removeListener('close', retry);
485
+ curClient.on('error', util.noop);
486
+ curClient.destroy();
487
+ curClient = null;
488
+ }
489
+ if (req._hasError || req._hasRespond) {
490
+ return;
491
+ }
492
+ if (err) {
508
493
  // Chrome 浏览器自动兼容 127.0.0.1 和 ::1
509
- if (util.notStarted(err)) {
510
- if (!newIp && (newIp = util.getLocalhostIP(err, req, originDomain, options.host))) {
511
- options.host = newIp;
512
- setHostsInfo(newIp);
513
- }
514
- } else if (isHttps && !options.ciphers && util.isCiphersError(err)) {
515
- extend(options, util.getTlsOptions(resRules));
516
- return send();
494
+ if (util.notStarted(err)) {
495
+ if (!newIp && (newIp = util.getLocalhostIP(err, req, originDomain, options.host))) {
496
+ options.host = newIp;
497
+ setHostsInfo(newIp);
517
498
  }
499
+ } else if (isHttps && !options.ciphers && util.isCiphersError(err)) {
500
+ extend(options, util.getTlsOptions(resRules));
501
+ return send();
518
502
  }
519
- if (retryCount >= maxRetryCount) {
520
- var toHttp;
521
- if (
503
+ }
504
+ if (retryCount >= maxRetryCount) {
505
+ var toHttp;
506
+ if (
522
507
  isHttps &&
523
508
  (!piped || req.noReqBody) &&
524
509
  util.checkTlsError(err) &&
525
510
  util.checkAuto2Http(req, ip, proxyUrl)
526
511
  ) {
527
- isHttps = false;
528
- toHttp = true;
529
- req.httpsTime = req.httpsTime || Date.now();
530
- req.useHttp = true;
531
- if (origProxy) {
532
- origProxy.isHttps = false;
533
- if (req._phost && !req._phost.port) {
534
- options.port = 80;
535
- origProxy.headers.host =
512
+ isHttps = false;
513
+ toHttp = true;
514
+ req.httpsTime = req.httpsTime || Date.now();
515
+ req.useHttp = true;
516
+ if (origProxy) {
517
+ origProxy.isHttps = false;
518
+ if (req._phost && !req._phost.port) {
519
+ options.port = 80;
520
+ origProxy.headers.host =
536
521
  req._phost.hostname + ':80';
537
- }
538
- setProxyAgent(options, origProxy);
539
- } else {
540
- setAgent(util.isLocalAddress(ip));
541
522
  }
523
+ setProxyAgent(options, origProxy);
524
+ } else {
525
+ setAgent(util.isLocalAddress(ip));
542
526
  }
543
- var code = err && err.code;
544
- if (
527
+ }
528
+ var code = err && err.code;
529
+ if (
545
530
  !toHttp &&
546
531
  (resetCount > 1 ||
547
532
  (code !== 'EPROTO' && code !== 'ECONNRESET') ||
548
533
  (piped && !req.noReqBody))
549
534
  ) {
550
- var stack = util.getErrorStack(
535
+ var stack = util.getErrorStack(
551
536
  err || new Error('socket connect timeout')
552
537
  );
553
- res.response(util.wrapGatewayError(stack));
554
- } else {
555
- ++resetCount;
556
- send();
557
- }
558
- return;
538
+ res.response(util.wrapGatewayError(stack));
539
+ } else {
540
+ ++resetCount;
541
+ send();
559
542
  }
560
- ++retryCount;
561
- if (proxyUrl) {
562
- if (X_RE.test(proxyUrl)) {
563
- proxyUrl = '';
564
- req._phost = undefined;
565
- if (isInternalProxy) {
566
- isHttps = origProto === 'https:';
567
- }
568
- req.curUrl = req.realUrl;
569
- delete options._proxyPort;
570
- rules.resolveHost(
543
+ return;
544
+ }
545
+ ++retryCount;
546
+ if (proxyUrl) {
547
+ if (X_RE.test(proxyUrl)) {
548
+ proxyUrl = '';
549
+ req._phost = undefined;
550
+ if (isInternalProxy) {
551
+ isHttps = origProto === 'https:';
552
+ }
553
+ req.curUrl = req.realUrl;
554
+ delete options._proxyPort;
555
+ rules.resolveHost(
571
556
  req,
572
557
  function (_err, _ip, _port, _host) {
573
558
  setAgent(util.isLocalAddress(_ip));
@@ -582,101 +567,101 @@ module.exports = function (req, res, next) {
582
567
  send();
583
568
  }
584
569
  );
585
- return;
586
- }
587
- } else if (
570
+ return;
571
+ }
572
+ } else if (
588
573
  retryXHost < 2 &&
589
574
  req.rules.host &&
590
575
  X_RE.test(req.rules.host.matcher)
591
576
  ) {
592
- ++maxRetryCount;
593
- ++retryXHost;
594
- if (retryXHost > 1) {
595
- req.curUrl = req.realUrl;
596
- delete options._proxyPort;
597
- rules.lookupHost(req, function (_err, _ip) {
598
- setHostsInfo(_ip);
599
- if (_err) {
600
- showDnsError(res, _err);
601
- return;
602
- }
603
- options.host = ip;
604
- options.port = originPort;
605
- send();
606
- });
607
- return;
608
- }
609
- } else if (
577
+ ++maxRetryCount;
578
+ ++retryXHost;
579
+ if (retryXHost > 1) {
580
+ req.curUrl = req.realUrl;
581
+ delete options._proxyPort;
582
+ rules.lookupHost(req, function (_err, _ip) {
583
+ setHostsInfo(_ip);
584
+ if (_err) {
585
+ showDnsError(res, _err);
586
+ return;
587
+ }
588
+ options.host = ip;
589
+ options.port = originPort;
590
+ send();
591
+ });
592
+ return;
593
+ }
594
+ } else if (
610
595
  isHttps &&
611
596
  util.checkAuto2Http(req, ip, proxyUrl)
612
597
  ) {
613
- ++maxRetryCount;
614
- if (maxRetryCount > 2 || util.checkTlsError(err)) {
615
- isHttps = false;
616
- req.httpsTime = req.httpsTime || Date.now();
617
- req.useHttp = true;
618
- setAgent(util.isLocalAddress(options.host));
619
- }
598
+ ++maxRetryCount;
599
+ if (maxRetryCount > 2 || util.checkTlsError(err)) {
600
+ isHttps = false;
601
+ req.httpsTime = req.httpsTime || Date.now();
602
+ req.useHttp = true;
603
+ setAgent(util.isLocalAddress(options.host));
620
604
  }
621
- send();
622
- };
623
- var send = function (sock) {
624
- if (req._hasError) {
625
- return;
626
- }
627
- req.useH2 = false;
628
- req.setServerPort(
605
+ }
606
+ send();
607
+ };
608
+ var send = function (sock) {
609
+ if (req._hasError) {
610
+ return;
611
+ }
612
+ req.useH2 = false;
613
+ req.setServerPort(
629
614
  options._proxyPort || options.port || (isHttps ? 443 : 80)
630
615
  );
631
- if (origPath != null && proxyUrl) {
632
- origPath = null;
633
- options.path =
616
+ if (origPath != null && proxyUrl) {
617
+ origPath = null;
618
+ options.path =
634
619
  (isHttps ? 'https:' : 'http:') +
635
620
  '//' +
636
621
  (headers.host || options.host) +
637
622
  (options.path || '/');
638
- }
639
- var useHttps = isHttps;
640
- if (sock) {
641
- options.agent = null;
642
- options.createConnection = function () {
643
- return sock;
644
- };
645
- } else {
646
- var proxyOpts = options._proxyOptions;
647
- if (proxyOpts) {
648
- if (!req.useHttpH2 || proxyOpts._phost) {
649
- setProxyAgent(options, proxyOpts);
650
- } else {
651
- options.host = proxyOpts.proxyHost;
652
- options.port = proxyOpts.proxyPort;
653
- useHttps = useHttps || isHttpsProxy;
654
- }
655
- delete options._proxyOptions;
623
+ }
624
+ var useHttps = isHttps;
625
+ if (sock) {
626
+ options.agent = null;
627
+ options.createConnection = function () {
628
+ return sock;
629
+ };
630
+ } else {
631
+ var proxyOpts = options._proxyOptions;
632
+ if (proxyOpts) {
633
+ if (!req.useHttpH2 || proxyOpts._phost) {
634
+ setProxyAgent(options, proxyOpts);
635
+ } else {
636
+ options.host = proxyOpts.proxyHost;
637
+ options.port = proxyOpts.proxyPort;
638
+ useHttps = useHttps || isHttpsProxy;
656
639
  }
640
+ delete options._proxyOptions;
657
641
  }
658
- options.protocol = useHttps ? 'https:' : 'http:';
659
- if (useHttps && !req.disable.secureOptions) {
660
- util.setSecureOptions(options);
661
- }
662
- try {
663
- var client = (useHttps ? https : http).request(
642
+ }
643
+ options.protocol = useHttps ? 'https:' : 'http:';
644
+ if (useHttps && !req.disable.secureOptions) {
645
+ util.setSecureOptions(options);
646
+ }
647
+ try {
648
+ var client = (useHttps ? https : http).request(
664
649
  options,
665
650
  res.response
666
651
  );
667
- curClient = client;
668
- req._clientReq = client;
669
- client.once('error', retry);
670
- client.once('socket', function (socket) {
671
- if (socket.connecting || socket._connecting) {
672
- if (TIMEOUT) {
673
- timer = setTimeout(function () {
674
- socket.destroy();
675
- timer = null;
676
- retry();
677
- }, TIMEOUT);
678
- }
679
- socket.once(
652
+ curClient = client;
653
+ req._clientReq = client;
654
+ client.once('error', retry);
655
+ client.once('socket', function (socket) {
656
+ if (socket.connecting || socket._connecting) {
657
+ if (TIMEOUT) {
658
+ timer = setTimeout(function () {
659
+ socket.destroy();
660
+ timer = null;
661
+ retry();
662
+ }, TIMEOUT);
663
+ }
664
+ socket.once(
680
665
  isHttpsProxy || isHttps
681
666
  ? 'secureConnect'
682
667
  : 'connect',
@@ -689,30 +674,30 @@ module.exports = function (req, res, next) {
689
674
  pipeClient(req, client);
690
675
  }
691
676
  );
692
- } else {
693
- retryCount = maxRetryCount;
694
- piped = true;
695
- pipeClient(req, client);
696
- socket.resume();
697
- }
698
- });
699
- } catch (e) {
700
- res.response(
677
+ } else {
678
+ retryCount = maxRetryCount;
679
+ piped = true;
680
+ pipeClient(req, client);
681
+ socket.resume();
682
+ }
683
+ });
684
+ } catch (e) {
685
+ res.response(
701
686
  util.wrapGatewayError(util.getErrorStack(e))
702
687
  );
703
- }
704
- };
705
- if (req.disable.clientIp || req.disable.clientIP) {
706
- delete headers[config.CLIENT_IP_HEAD];
707
- } else {
708
- var forwardedFor = util.getMatcherValue(
688
+ }
689
+ };
690
+ if (req.disable.clientIp || req.disable.clientIP) {
691
+ delete headers[clientIpKey];
692
+ } else {
693
+ var forwardedFor = util.getMatcherValue(
709
694
  resRules.forwardedFor
710
695
  );
711
- if (net.isIP(forwardedFor)) {
712
- headers[config.CLIENT_IP_HEAD] = forwardedFor;
713
- } else if (net.isIP(req._customXFF)) {
714
- headers[config.CLIENT_IP_HEAD] = req._customXFF;
715
- } else if (
696
+ if (net.isIP(forwardedFor)) {
697
+ headers[clientIpKey] = forwardedFor;
698
+ } else if (req._customXFF) {
699
+ headers[clientIpKey] = req._customXFF;
700
+ } else if (
716
701
  (!options.isPlugin &&
717
702
  !req.enable.clientIp &&
718
703
  !req.enable.clientIP &&
@@ -720,76 +705,76 @@ module.exports = function (req, res, next) {
720
705
  (isHttps || isSocks || !proxyUrl)) ||
721
706
  util.isLocalAddress(req.clientIp)
722
707
  ) {
723
- delete headers[config.CLIENT_IP_HEAD];
724
- } else {
725
- headers[config.CLIENT_IP_HEAD] = req.clientIp;
726
- }
708
+ delete headers[clientIpKey];
709
+ } else {
710
+ headers[clientIpKey] = req.clientIp;
727
711
  }
728
- util.deleteReqHeaders(req);
729
- var optHeaders = options.headers;
730
- var transfer =
712
+ }
713
+ util.deleteReqHeaders(req);
714
+ var optHeaders = options.headers;
715
+ var transfer =
731
716
  options.method === 'DELETE' &&
732
717
  optHeaders['transfer-encoding'];
733
- if (transfer) {
734
- delete optHeaders['transfer-encoding'];
718
+ if (transfer) {
719
+ delete optHeaders['transfer-encoding'];
720
+ }
721
+ var clientId = optHeaders[config.CLIENT_ID_HEADER];
722
+ if (clientId) {
723
+ if (!options.isPlugin && !req._customClientId && !util.isKeepClientId(req, proxyUrl)) {
724
+ req._origClientId = clientId;
725
+ util.removeClientId(optHeaders);
735
726
  }
736
- var clientId = optHeaders[config.CLIENT_ID_HEADER];
737
- if (clientId) {
738
- if (!options.isPlugin && !req._customClientId && !util.isKeepClientId(req, proxyUrl)) {
739
- req._origClientId = clientId;
740
- util.removeClientId(optHeaders);
741
- }
742
- req.setClientId && req.setClientId(clientId);
743
- } else {
744
- util.setClientId(
727
+ req.setClientId && req.setClientId(clientId);
728
+ } else {
729
+ util.setClientId(
745
730
  optHeaders,
746
731
  req.enable,
747
732
  req.disable,
748
733
  req.clientIp,
749
734
  isInternalProxy
750
735
  );
751
- }
752
- if (
736
+ }
737
+ if (
753
738
  req.useH2 &&
754
739
  (isInternalProxy ||
755
740
  headers[config.HTTPS_FIELD] ||
756
741
  options.isPlugin)
757
742
  ) {
758
- headers[config.ALPN_PROTOCOL_HEADER] = 'h2';
759
- }
760
- options.headers = optHeaders = formatHeaders(
743
+ headers[config.ALPN_PROTOCOL_HEADER] = 'h2';
744
+ }
745
+ options.headers = optHeaders = formatHeaders(
761
746
  optHeaders,
762
747
  req.rawHeaderNames
763
748
  );
764
- delete headers[config.WEBUI_HEAD];
765
- delete headers[config.HTTPS_FIELD];
766
- delete headers[config.ALPN_PROTOCOL_HEADER];
767
- if (transfer) {
768
- optHeaders['Transfer-Encoding'] = transfer;
769
- }
770
- if (options.isPlugin) {
771
- optHeaders[config.PLUGIN_HOOK_NAME_HEADER] =
749
+ delete headers[config.WEBUI_HEAD];
750
+ delete headers[config.HTTPS_FIELD];
751
+ delete headers[config.ALPN_PROTOCOL_HEADER];
752
+ if (transfer) {
753
+ optHeaders['Transfer-Encoding'] = transfer;
754
+ }
755
+ if (options.isPlugin) {
756
+ optHeaders[config.PLUGIN_HOOK_NAME_HEADER] =
772
757
  config.PLUGIN_HOOKS.HTTP;
773
- }
774
- req.noReqBody = !util.hasRequestBody(req);
775
- if (
758
+ }
759
+ req.noReqBody = !util.hasRequestBody(req);
760
+ if (
776
761
  req.method === 'DELETE' &&
777
762
  (req._hasInjectBody ||
778
763
  req.headers['transfer-encoding'] ||
779
764
  req.headers['content-length'] > 0)
780
765
  ) {
781
- req.useH2 = false;
782
- }
783
- req.setServerPort(
766
+ req.useH2 = false;
767
+ }
768
+ req.setServerPort(
784
769
  options._proxyPort || options.port || (isHttps ? 443 : 80)
785
770
  );
786
- req.options = options;
787
- isHttps &&
771
+ req.options = options;
772
+ isHttps &&
788
773
  util.setClientCert(options, key, cert, isPfx, cacheKey);
789
- util.addMatchedRules(req);
790
- h2.request(req, res, send);
791
- }
792
- },
774
+ util.addMatchedRules(req);
775
+ h2.request(req, res, send);
776
+ }
777
+ },
793
778
  req.pluginRules,
794
779
  req.rulesFileMgr,
795
780
  req.headerRulesMgr
@@ -833,7 +818,7 @@ module.exports = function (req, res, next) {
833
818
  delete headers[config.PROXY_ID_HEADER];
834
819
  }
835
820
  if (req.disable.additionalHeaders) {
836
- delete headers[config.ADDITIONAL_HEAD];
821
+ delete headers[util.ADDITIONAL_HEAD];
837
822
  }
838
823
  util.drain(req, function () {
839
824
  readFirstChunk(req, res, _res, function (firstChunk) {
@@ -1140,12 +1125,12 @@ module.exports = function (req, res, next) {
1140
1125
 
1141
1126
  var bodyFile = hasResBody
1142
1127
  ? getWriterFile(
1143
- util.getRuleFile(resRules.resWrite),
1128
+ util.getWriteFilePath(resRules.resWrite),
1144
1129
  _res.statusCode
1145
1130
  )
1146
1131
  : null;
1147
1132
  var rawFile = getWriterFile(
1148
- util.getRuleFile(resRules.resWriteRaw),
1133
+ util.getWriteFilePath(resRules.resWriteRaw),
1149
1134
  _res.statusCode
1150
1135
  );
1151
1136
  util.getFileWriters(