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.
- package/assets/js/log.js +8 -4
- package/bin/util.js +1 -1
- package/biz/index.js +12 -10
- package/biz/webui/cgi-bin/certs/active.js +6 -0
- package/biz/webui/cgi-bin/certs/remove.js +0 -1
- package/biz/webui/cgi-bin/certs/upload.js +0 -1
- package/biz/webui/cgi-bin/util.js +7 -20
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +43 -43
- package/biz/webui/lib/index.js +10 -13
- package/lib/config.js +17 -36
- package/lib/handlers/file-proxy.js +2 -1
- package/lib/handlers/http-proxy.js +1 -1
- package/lib/https/ca.js +34 -27
- package/lib/https/h2.js +1 -1
- package/lib/https/index.js +21 -17
- package/lib/index.js +1 -1
- package/lib/init.js +13 -12
- package/lib/inspectors/req.js +13 -10
- package/lib/inspectors/res.js +375 -390
- package/lib/inspectors/rules.js +11 -0
- package/lib/plugins/compat.js +108 -0
- package/lib/plugins/get-plugins-sync.js +1 -4
- package/lib/plugins/index.js +92 -284
- package/lib/plugins/load-plugin.js +205 -223
- package/lib/plugins/module-paths.js +3 -4
- package/lib/plugins/proxy.js +4 -7
- package/lib/rules/index.js +69 -66
- package/lib/rules/protocols.js +6 -0
- package/lib/rules/rules.js +44 -32
- package/lib/rules/util.js +30 -0
- package/lib/service/composer.js +5 -5
- package/lib/service/util.js +7 -21
- package/lib/tunnel.js +15 -12
- package/lib/upgrade.js +9 -10
- package/lib/util/common.js +171 -48
- package/lib/util/file-mgr.js +3 -7
- package/lib/util/index.js +101 -143
- package/package.json +1 -1
- package/README-en_US.md +0 -80
- package/biz/webui/htdocs/img/assistant.svg +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var path = require('path');
|
|
2
|
+
var common = require('../util/common');
|
|
2
3
|
var config = require('../config');
|
|
3
4
|
|
|
4
5
|
var PLUGIN_DIR_RE = /[/\\]whistle\.[a-z\d_-]+[/\\]?$/;
|
|
@@ -117,11 +118,9 @@ function formatPath(dir, prefix) {
|
|
|
117
118
|
return null;
|
|
118
119
|
}
|
|
119
120
|
if (/(?:^|\/|\\)node_modules[\\\/]?$/.test(dir)) {
|
|
120
|
-
return
|
|
121
|
+
return common.formatPathSep(dir);
|
|
121
122
|
}
|
|
122
|
-
return path
|
|
123
|
-
.resolve(dir, typeof prefix === 'string' ? prefix : '', 'node_modules')
|
|
124
|
-
.replace(/\\/g, '/');
|
|
123
|
+
return common.formatPathSep(path.resolve(dir, typeof prefix === 'string' ? prefix : '', 'node_modules'));
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
function getGlobalDir() {
|
package/lib/plugins/proxy.js
CHANGED
|
@@ -93,12 +93,12 @@ function createSocket(opts, cb) {
|
|
|
93
93
|
var clientIp = common.removeIPV6Prefix(opts.clientIp);
|
|
94
94
|
var clientPort = opts.clientPort;
|
|
95
95
|
if (clientIp && net.isIP(clientIp)) {
|
|
96
|
-
headers[
|
|
96
|
+
headers[common.CLIENT_IP_HEADER] = clientIp;
|
|
97
97
|
}
|
|
98
98
|
if (clientPort > 0 && clientPort < 65536) {
|
|
99
99
|
headers['x-whistle-client-port'] = clientPort;
|
|
100
100
|
}
|
|
101
|
-
headers[
|
|
101
|
+
headers[common.ACK_HEADER] = '1';
|
|
102
102
|
client = http.request({
|
|
103
103
|
host: proxyIp,
|
|
104
104
|
port: proxyPort,
|
|
@@ -110,15 +110,12 @@ function createSocket(opts, cb) {
|
|
|
110
110
|
client.once('connect', function (res, socket) {
|
|
111
111
|
socket.on('error', handleCb);
|
|
112
112
|
if (res.statusCode !== 200) {
|
|
113
|
-
var err = new Error(
|
|
114
|
-
'Tunneling socket could not be established, statusCode=' +
|
|
115
|
-
res.statusCode
|
|
116
|
-
);
|
|
113
|
+
var err = new Error('Tunneling socket could not be established, statusCode=' + res.statusCode);
|
|
117
114
|
err.statusCode = res.statusCode;
|
|
118
115
|
socket.destroy();
|
|
119
116
|
return handleCb(err);
|
|
120
117
|
}
|
|
121
|
-
if (res.headers[
|
|
118
|
+
if (res.headers[common.ALLOW_ACK]) {
|
|
122
119
|
socket.write('1');
|
|
123
120
|
}
|
|
124
121
|
handleCb(null, socket, res);
|
package/lib/rules/index.js
CHANGED
|
@@ -55,6 +55,7 @@ exports.parse = rules.parse.bind(rules);
|
|
|
55
55
|
exports.append = rules.append.bind(rules);
|
|
56
56
|
exports.resolveSNICallback = rules.resolveSNICallback.bind(rules);
|
|
57
57
|
exports.resolveHost = rules.resolveHost.bind(rules);
|
|
58
|
+
exports.getGRuleList = rules.getGRuleList.bind(rules);
|
|
58
59
|
exports.resolveInternalHost = rules.resolveInternalHost.bind(rules);
|
|
59
60
|
exports.resolveProxy = rules.resolveProxy.bind(rules);
|
|
60
61
|
exports.resolveEnable = rules.resolveEnable.bind(rules);
|
|
@@ -153,12 +154,11 @@ exports.getProxy = function (url, req, callback) {
|
|
|
153
154
|
} else {
|
|
154
155
|
proxy = resolveRulesFromList([pRules, rules, fRules, hRules], 'resolveProxy', req, hostValue);
|
|
155
156
|
}
|
|
156
|
-
var proxyHostOnly
|
|
157
|
-
var proxyHost =
|
|
158
|
-
proxyHostOnly ||
|
|
159
|
-
util.isEnable(req, 'proxyHost') ||
|
|
160
|
-
isProxyEnable(req, 'proxyHost');
|
|
157
|
+
var proxyHostOnly;
|
|
158
|
+
var proxyHost = util.isEnable(req, 'proxyHost') || isProxyEnable(req, 'proxyHost');
|
|
161
159
|
if (proxy) {
|
|
160
|
+
proxyHostOnly = isLineProp(proxy, 'proxyHostOnly');
|
|
161
|
+
proxyHost = proxyHost || proxyHostOnly;
|
|
162
162
|
var protocol = proxy.matcher.substring(0, proxy.matcher.indexOf(':'));
|
|
163
163
|
ignoreProxy =
|
|
164
164
|
!filter['ignore:' + protocol] &&
|
|
@@ -252,14 +252,15 @@ exports.getProxy = function (url, req, callback) {
|
|
|
252
252
|
if (!pacUrl) {
|
|
253
253
|
return setHost() || callback();
|
|
254
254
|
}
|
|
255
|
+
var auth;
|
|
255
256
|
if (AUTH_RE.test(pacUrl)) {
|
|
256
|
-
|
|
257
|
-
req._pacAuth = auth;
|
|
257
|
+
auth = RegExp.$1;
|
|
258
258
|
pacUrl = pacUrl.substring(auth.length + 1);
|
|
259
259
|
}
|
|
260
|
-
pacUrl = util.
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
if (!util.isUrl(pacUrl) && !(pacUrl = util.joinPath(pacRule.root, pacUrl))) {
|
|
261
|
+
return setHost() || callback();
|
|
262
|
+
}
|
|
263
|
+
req._pacAuth = auth;
|
|
263
264
|
var pac = cachedPacs[pacUrl];
|
|
264
265
|
if (pac) {
|
|
265
266
|
delete cachedPacs[pacUrl];
|
|
@@ -476,43 +477,49 @@ function handleDynamicRules(script, req, res, cb) {
|
|
|
476
477
|
}, null, null, null, req);
|
|
477
478
|
}
|
|
478
479
|
|
|
479
|
-
function
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
480
|
+
function resolvePluginVars(req, list) {
|
|
481
|
+
var varMap = {};
|
|
482
|
+
var globalValue;
|
|
483
|
+
var pList;
|
|
484
|
+
list.forEach(function (item) {
|
|
485
|
+
if (item.matcher[0] !== 'P') {
|
|
486
|
+
if (!globalValue) {
|
|
487
|
+
globalValue = item;
|
|
488
|
+
}
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
var value = util.getMatcherValue(item);
|
|
492
|
+
var index = value.indexOf(PLUGIN_VAR_RE.test(value) ? '.' : '=');
|
|
493
|
+
if (index !== -1) {
|
|
494
|
+
var name = value.substring(0, index);
|
|
495
|
+
var plugin = getPluginName(name);
|
|
496
|
+
if (!plugin) {
|
|
489
497
|
return;
|
|
490
498
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
var
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
value = value.substring(index + 1);
|
|
500
|
-
if (value) {
|
|
501
|
-
pList = pList || [];
|
|
502
|
-
pList.push(item);
|
|
503
|
-
var list = varMap[name] || [];
|
|
504
|
-
varMap[name] = list;
|
|
505
|
-
if (list.indexOf(value) === -1) {
|
|
506
|
-
list.push(value);
|
|
507
|
-
}
|
|
499
|
+
value = value.substring(index + 1);
|
|
500
|
+
if (value) {
|
|
501
|
+
pList = pList || [];
|
|
502
|
+
pList.push(item);
|
|
503
|
+
var list = varMap[name] || [];
|
|
504
|
+
varMap[name] = list;
|
|
505
|
+
if (list.indexOf(value) === -1) {
|
|
506
|
+
list.push(value);
|
|
508
507
|
}
|
|
509
508
|
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
req.rules = req.rules || {};
|
|
512
|
+
req._pluginVars = varMap;
|
|
513
|
+
req.rules.P = pList;
|
|
514
|
+
req.rules.G = globalValue;
|
|
515
|
+
req.globalValue = util.getMatcherValue(globalValue);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
exports.resolvePluginVars = resolvePluginVars;
|
|
519
|
+
|
|
520
|
+
exports.resolveRulesFile = function (req, callback) {
|
|
521
|
+
!req._resolvedG && req.rules.G && resolvePluginVars(req, req.rules.G.list);
|
|
522
|
+
req._resolvedG = true;
|
|
516
523
|
var rule = req.rules.rulesFile;
|
|
517
524
|
handleDynamicRules(rule, req, null, function (text, vals) {
|
|
518
525
|
if (text) {
|
|
@@ -528,9 +535,8 @@ function resolveRulesFile(req, callback) {
|
|
|
528
535
|
util.mergeRules(req, text);
|
|
529
536
|
callback();
|
|
530
537
|
});
|
|
531
|
-
}
|
|
538
|
+
};
|
|
532
539
|
|
|
533
|
-
exports.resolveRulesFile = resolveRulesFile;
|
|
534
540
|
exports.resolveResRulesFile = function (req, res, callback) {
|
|
535
541
|
var rule = req.rules && req.rules.resScript;
|
|
536
542
|
handleDynamicRules(
|
|
@@ -553,7 +559,7 @@ exports.resolveResRulesFile = function (req, res, callback) {
|
|
|
553
559
|
function getValue(req, key, keep) {
|
|
554
560
|
var value = req.headers[key];
|
|
555
561
|
if (value) {
|
|
556
|
-
if (!keep && config.strict) {
|
|
562
|
+
if (!req.fromComposer && !keep && (config.strict || (!config.enableRequestHeaderRules && !config.multiEnv))) {
|
|
557
563
|
value = null;
|
|
558
564
|
} else {
|
|
559
565
|
req.rulesHeaders[key] = value;
|
|
@@ -566,6 +572,10 @@ function getValue(req, key, keep) {
|
|
|
566
572
|
return value;
|
|
567
573
|
}
|
|
568
574
|
|
|
575
|
+
function getPluginName(key) {
|
|
576
|
+
return exports.getPlugin(key);
|
|
577
|
+
}
|
|
578
|
+
|
|
569
579
|
function initHeaderRules(req, needBodyFilters) {
|
|
570
580
|
if (req._bodyFilters !== undefined) {
|
|
571
581
|
return;
|
|
@@ -597,8 +607,15 @@ function initHeaderRules(req, needBodyFilters) {
|
|
|
597
607
|
}
|
|
598
608
|
}
|
|
599
609
|
var curVars = rules._globalPluginVars;
|
|
610
|
+
var globalVars = {};
|
|
600
611
|
var value;
|
|
601
|
-
req._globalPluginVars =
|
|
612
|
+
req._globalPluginVars = globalVars;
|
|
613
|
+
Object.keys(curVars).forEach(function (key) {
|
|
614
|
+
if (getPluginName(key)) {
|
|
615
|
+
value = curVars[key];
|
|
616
|
+
globalVars[key] = value;
|
|
617
|
+
}
|
|
618
|
+
});
|
|
602
619
|
if (ruleValue) {
|
|
603
620
|
var file = 'Header Rules';
|
|
604
621
|
var vals = util.toPrivateValues(util.parseJSON(kvHeader), file);
|
|
@@ -611,25 +628,11 @@ function initHeaderRules(req, needBodyFilters) {
|
|
|
611
628
|
req._bodyFilters = rules._rules._bodyFilters.concat(bodyFilters);
|
|
612
629
|
}
|
|
613
630
|
var headerVars = rulesMgr._globalPluginVars;
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
var headerVal = headerVars[key];
|
|
621
|
-
var curVal = curVars[key];
|
|
622
|
-
if (curVal && headerVal) {
|
|
623
|
-
vars[key] = headerVal.concat(curVal);
|
|
624
|
-
}
|
|
625
|
-
value = vars[key];
|
|
626
|
-
req._globalPluginVars[key] = value;
|
|
627
|
-
});
|
|
628
|
-
} else {
|
|
629
|
-
Object.keys(curVars).forEach(function (key) {
|
|
630
|
-
if (!exports.getPlugin || exports.getPlugin(key)) {
|
|
631
|
-
value = curVars[key];
|
|
632
|
-
req._globalPluginVars[key] = value;
|
|
631
|
+
Object.keys(headerVars).forEach(function (key) {
|
|
632
|
+
var headerVal = getPluginName(key) && headerVars[key];
|
|
633
|
+
if (headerVal) {
|
|
634
|
+
var curVal = curVars[key];
|
|
635
|
+
globalVars[key] = curVal ? curVal.concat(headerVal) : headerVal;
|
|
633
636
|
}
|
|
634
637
|
});
|
|
635
638
|
}
|
package/lib/rules/protocols.js
CHANGED
|
@@ -152,9 +152,13 @@ var aliasProtocols = {
|
|
|
152
152
|
includeFilter: 'filter',
|
|
153
153
|
P: 'G'
|
|
154
154
|
};
|
|
155
|
+
var protocolsWithoutG = protocols.slice(1);
|
|
155
156
|
var reqProtocols = protocols.filter(function (name) {
|
|
156
157
|
return pureResProtocols.indexOf(name) === -1;
|
|
157
158
|
});
|
|
159
|
+
var reqProtosWithoutG = reqProtocols.filter(function (name) {
|
|
160
|
+
return name !== 'G';
|
|
161
|
+
});
|
|
158
162
|
|
|
159
163
|
var RULE_PROTO_RE = /^([\w.-]+):\/\//;
|
|
160
164
|
|
|
@@ -222,8 +226,10 @@ exports.multiMatchs = [
|
|
|
222
226
|
'resScript'
|
|
223
227
|
];
|
|
224
228
|
exports.protocols = protocols;
|
|
229
|
+
exports.protocolsWithoutG = protocolsWithoutG;
|
|
225
230
|
exports.pureResProtocols = pureResProtocols;
|
|
226
231
|
exports.reqProtocols = reqProtocols;
|
|
232
|
+
exports.reqProtosWithoutG = reqProtosWithoutG;
|
|
227
233
|
exports.resProtocols = resProtocols;
|
|
228
234
|
exports.aliasProtocols = aliasProtocols;
|
|
229
235
|
|
package/lib/rules/rules.js
CHANGED
|
@@ -27,7 +27,9 @@ var ROOT_PLUGIN_RE = /[\\/]whistle\.([a-z\d_-]+)$/;
|
|
|
27
27
|
var TPL_KEY_RE = /\{\{\s*%?ruleValue\s*\}\}/g;
|
|
28
28
|
var END_RE = /\$$/;
|
|
29
29
|
var protocols = protoMgr.protocols;
|
|
30
|
+
var protocolsWithoutG = protoMgr.protocolsWithoutG;
|
|
30
31
|
var reqProtocols = protoMgr.reqProtocols;
|
|
32
|
+
var reqProtosWithoutG = protoMgr.reqProtosWithoutG;
|
|
31
33
|
var pureResProtocols = protoMgr.pureResProtocols;
|
|
32
34
|
var multiMatchs = protoMgr.multiMatchs;
|
|
33
35
|
var aliasProtocols = protoMgr.aliasProtocols;
|
|
@@ -36,7 +38,7 @@ var PROXY_RE =
|
|
|
36
38
|
/^x?(socks|proxy|https?-proxy|internal-proxy|internal-https?-proxy|https2http-proxy|http2https-proxy):\/\//;
|
|
37
39
|
var VAR_RE = /\${([^{}]+)}/g;
|
|
38
40
|
var NO_SCHEMA_RE = /^\/\/[^/]/;
|
|
39
|
-
var WILDCARD_RE = /^(\$?((?:
|
|
41
|
+
var WILDCARD_RE = /^(\$?((?:[a-z*]+):\/\/)?([^/?]*))/;
|
|
40
42
|
var RULE_KEY_RE = /^\$\{(\S+)\}$/;
|
|
41
43
|
var VALUE_KEY_RE = /^\{(\S+)\}$/;
|
|
42
44
|
var LINE_END_RE = /\n|\r\n|\r/;
|
|
@@ -44,10 +46,9 @@ var LOCAL_RULE_RE =
|
|
|
44
46
|
/^https?:\/\/local\.(?:whistlejs\.com|wproxy\.org)(:realPort)?(?:\/|\?|$)/;
|
|
45
47
|
var PATH_RE = /^<.*>$/;
|
|
46
48
|
var VALUE_RE = /^\(.*\)$/;
|
|
47
|
-
var REG_URL_RE = /^((?:[
|
|
48
|
-
var LIKE_REG_URL_RE = /^(?:(?:https?|wss?|tunnel)
|
|
49
|
-
var LIKE_REG_URL_RE2 =
|
|
50
|
-
/^(?:(?:https?|wss?|tunnel):\/\/)?\.[^./?]+\.[^/?]+\/[^?*]*\*/;
|
|
49
|
+
var REG_URL_RE = /^((?:[a-z*]+:)?\/\/)?([^/?]*)/;
|
|
50
|
+
var LIKE_REG_URL_RE = /^(?:(?:(?:https?|wss?|tunnel):)?\/\/)?\*+\/[^?*]*\*/;
|
|
51
|
+
var LIKE_REG_URL_RE2 = /^(?:(?:(?:https?|wss?|tunnel):)?\/\/)?\.[^./?]+\.[^/?]+\/[^?*]*\*/;
|
|
51
52
|
var DOT_DOMAIN_RE = /^\.[^./?]+\.[^/?]/;
|
|
52
53
|
var REG_URL_SYMBOL_RE = /^(\^+)/;
|
|
53
54
|
var PATTERN_FILTER_RE = /^(?:filter|ignore):\/\/(.+)\/(i)?$/;
|
|
@@ -93,13 +94,13 @@ var ENABLE_PROXY_RE =
|
|
|
93
94
|
var PLUGIN_VAR_RE = /^%([a-z\d_\-]+)([=.])([^\s]*)/;
|
|
94
95
|
var EXACT_IGNORE_RE = /^ignore:\/\/(pattern|matcher|operator|operation)[=:](.+)$/;
|
|
95
96
|
var EXACT_SKIP_RE = /^(pattern|matcher|operator|operation)[=:](.+)$/;
|
|
96
|
-
var
|
|
97
|
+
var FILE_PROTO_RE = /^x?((raw)?file|tpl|jsonp|dust):\/\//;
|
|
97
98
|
var NO_PROTO_RE = /[^\w!*|.-]/;
|
|
98
99
|
var SKIP_RE = /^skip:\/\//;
|
|
99
100
|
var SUB_VAR_RE = /\$\{RegExp\.\$([&\d])\}/g;
|
|
100
101
|
var mIndex = 0;
|
|
101
102
|
var mNow = Date.now();
|
|
102
|
-
var IS_JSON =
|
|
103
|
+
var IS_JSON = Symbol('isJson');
|
|
103
104
|
|
|
104
105
|
function getMFlag() {
|
|
105
106
|
if (mIndex === Number.MAX_SAFE_INTEGER) {
|
|
@@ -181,7 +182,7 @@ function isRegUrl(url, isCheck) {
|
|
|
181
182
|
if (!protocol || protocol === '//') {
|
|
182
183
|
protocol = '[a-z]+://';
|
|
183
184
|
} else {
|
|
184
|
-
protocol = util.escapeRegExp(protocol).replace(/\*+/, '([a-z:]
|
|
185
|
+
protocol = util.escapeRegExp(protocol).replace(/\*+/, '([a-z:]*)');
|
|
185
186
|
}
|
|
186
187
|
if (startWithDot) {
|
|
187
188
|
domain = domain.substring(1);
|
|
@@ -290,7 +291,7 @@ function getValue(url, start, end, lineProps) {
|
|
|
290
291
|
}
|
|
291
292
|
|
|
292
293
|
function getFiles(path) {
|
|
293
|
-
return
|
|
294
|
+
return FILE_PROTO_RE.test(path) ? util.removeProtocol(path, true).split('|') : null;
|
|
294
295
|
}
|
|
295
296
|
|
|
296
297
|
function setProtocol(target, source) {
|
|
@@ -333,7 +334,7 @@ function joinQuery(query1, query2) {
|
|
|
333
334
|
: '&';
|
|
334
335
|
return query1 + sep + query2;
|
|
335
336
|
}
|
|
336
|
-
function
|
|
337
|
+
function joinUrl(a, b) {
|
|
337
338
|
if (!a || !b) {
|
|
338
339
|
return a + b;
|
|
339
340
|
}
|
|
@@ -789,7 +790,7 @@ function getValueFor(key, vals, file) {
|
|
|
789
790
|
return;
|
|
790
791
|
}
|
|
791
792
|
var key1 = util.getInlineKey(key, file);
|
|
792
|
-
var val = vals
|
|
793
|
+
var val = vals ? vals[key1] : undefined;
|
|
793
794
|
if (val !== undefined) {
|
|
794
795
|
val = vals[key1] = val && typeof val == 'object' ? JSON.stringify(val) : val;
|
|
795
796
|
} else {
|
|
@@ -945,13 +946,13 @@ function resolveRuleList(req, list, vals, index, isFilter, isEnableProxy, host)
|
|
|
945
946
|
result = extend(
|
|
946
947
|
{
|
|
947
948
|
files: files,
|
|
948
|
-
url:
|
|
949
|
+
url: joinUrl(matcher, filePath)
|
|
949
950
|
},
|
|
950
951
|
rule
|
|
951
952
|
);
|
|
952
953
|
if (files && filePath) {
|
|
953
954
|
result.files = files.map(function (file) {
|
|
954
|
-
return
|
|
955
|
+
return joinUrl(file, filePath);
|
|
955
956
|
});
|
|
956
957
|
result.rawFiles = files;
|
|
957
958
|
}
|
|
@@ -1027,17 +1028,13 @@ function resolveRuleList(req, list, vals, index, isFilter, isEnableProxy, host)
|
|
|
1027
1028
|
}
|
|
1028
1029
|
} else if (rule.wildcard) {
|
|
1029
1030
|
var wildcard = rule.wildcard;
|
|
1030
|
-
var
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
for (var k = 1; k < 9; k++) {
|
|
1036
|
-
regObj[k] = RegExp['$' + (k + 1)];
|
|
1031
|
+
var matched = wildcard.preMatch.exec(curUrl);
|
|
1032
|
+
if (matched && checkFilter()) {
|
|
1033
|
+
var regObj = {};
|
|
1034
|
+
for (var k = 0; k < 9; k++) {
|
|
1035
|
+
regObj[k] = matched[k + 1] || '';
|
|
1037
1036
|
}
|
|
1038
|
-
|
|
1039
|
-
if (hostname != null && checkFilter()) {
|
|
1040
|
-
filePath = curUrl.substring(hostname.length);
|
|
1037
|
+
filePath = curUrl.substring(regObj[0].length);
|
|
1041
1038
|
var wPath = wildcard.path;
|
|
1042
1039
|
if (wildcard.isExact) {
|
|
1043
1040
|
if (
|
|
@@ -1171,6 +1168,7 @@ function parseWildcard(pattern, not) {
|
|
|
1171
1168
|
var startWithDot = DOT_DOMAIN_RE.test(domain);
|
|
1172
1169
|
if (
|
|
1173
1170
|
!startWithDot &&
|
|
1171
|
+
protocol.indexOf('*') === -1 &&
|
|
1174
1172
|
domain.indexOf('*') === -1 &&
|
|
1175
1173
|
domain.indexOf('~') === -1
|
|
1176
1174
|
) {
|
|
@@ -1179,8 +1177,8 @@ function parseWildcard(pattern, not) {
|
|
|
1179
1177
|
if (not) {
|
|
1180
1178
|
return false;
|
|
1181
1179
|
}
|
|
1182
|
-
|
|
1183
|
-
var path =
|
|
1180
|
+
var restPath = pattern.substring(preMatch.length);
|
|
1181
|
+
var path = restPath || '/';
|
|
1184
1182
|
var isExact = preMatch.indexOf('$') === 0;
|
|
1185
1183
|
if (isExact) {
|
|
1186
1184
|
preMatch = preMatch.substring(1);
|
|
@@ -1190,7 +1188,8 @@ function parseWildcard(pattern, not) {
|
|
|
1190
1188
|
if (hasQuery && index === 0) {
|
|
1191
1189
|
path = '/' + path;
|
|
1192
1190
|
}
|
|
1193
|
-
var
|
|
1191
|
+
var dLen = domain.length;
|
|
1192
|
+
var allowMatchPath = dLen > 2 && !NON_STAR_RE.test(domain);
|
|
1194
1193
|
if (allowMatchPath) {
|
|
1195
1194
|
preMatch = '[^?]*';
|
|
1196
1195
|
} else {
|
|
@@ -1201,11 +1200,10 @@ function parseWildcard(pattern, not) {
|
|
|
1201
1200
|
) {
|
|
1202
1201
|
preMatch += '*';
|
|
1203
1202
|
}
|
|
1204
|
-
var dLen = domain.length;
|
|
1205
1203
|
preMatch = util
|
|
1206
1204
|
.escapeRegExp(preMatch)
|
|
1207
1205
|
.replace(DOMAIN_STAR_RE, domainToRegExp);
|
|
1208
|
-
if (domain[dLen - 1] !== '*' && domain.indexOf(':') === -1) {
|
|
1206
|
+
if (dLen && domain[dLen - 1] !== '*' && domain.indexOf(':') === -1) {
|
|
1209
1207
|
preMatch += '(?::\\d+)?';
|
|
1210
1208
|
}
|
|
1211
1209
|
if (startWithDot) {
|
|
@@ -1218,7 +1216,7 @@ function parseWildcard(pattern, not) {
|
|
|
1218
1216
|
preMatch = '[a-z]+:' + preMatch;
|
|
1219
1217
|
}
|
|
1220
1218
|
preMatch =
|
|
1221
|
-
'^(' + preMatch + ')' + (allowMatchPath ? util.escapeRegExp(path, true) : '');
|
|
1219
|
+
'^(' + preMatch + (restPath ? '' : '[^/?]*') + ')' + (allowMatchPath ? util.escapeRegExp(path, true) : '');
|
|
1222
1220
|
|
|
1223
1221
|
return {
|
|
1224
1222
|
preMatch: new RegExp(preMatch),
|
|
@@ -1411,9 +1409,9 @@ function parseRule(rulesMgr, pattern, matcher, raw, root, options, file) {
|
|
|
1411
1409
|
function isPattern(item) {
|
|
1412
1410
|
return (
|
|
1413
1411
|
PORT_PATTERN_RE.test(item) ||
|
|
1414
|
-
NO_SCHEMA_RE.test(item) ||
|
|
1415
1412
|
isExactPattern(item) ||
|
|
1416
|
-
isRegUrl(item, true) ||
|
|
1413
|
+
isRegUrl(item, true) || // 缓存 regUrl
|
|
1414
|
+
NO_SCHEMA_RE.test(item) ||
|
|
1417
1415
|
isNegativePattern(item) ||
|
|
1418
1416
|
WEB_PROTOCOL_RE.test(item) ||
|
|
1419
1417
|
util.isRegExp(item)
|
|
@@ -1655,6 +1653,9 @@ function resolveMatchFilter(list) {
|
|
|
1655
1653
|
} else {
|
|
1656
1654
|
var isHeader = propName !== 'env' && propName !== 'chance' && propName !== 'probability';
|
|
1657
1655
|
var index = value.indexOf('=');
|
|
1656
|
+
if (isHeader && index === -1) {
|
|
1657
|
+
index = value.indexOf(':');
|
|
1658
|
+
}
|
|
1658
1659
|
var key = index === -1 ? value : value.substring(0, index);
|
|
1659
1660
|
if (isHeader) {
|
|
1660
1661
|
key = key.toLowerCase();
|
|
@@ -1843,6 +1844,9 @@ function matchFilter(url, filter, req) {
|
|
|
1843
1844
|
if (filter.from === 'composer') {
|
|
1844
1845
|
return filter.not ? !req.fromComposer : req.fromComposer;
|
|
1845
1846
|
}
|
|
1847
|
+
if (filter.from === 'internalPath') {
|
|
1848
|
+
return filter.not ? !req.fromInternalPath : req.fromInternalPath;
|
|
1849
|
+
}
|
|
1846
1850
|
if (filter.from === 'sni') {
|
|
1847
1851
|
return filter.not ? !req.useSNI : req.useSNI;
|
|
1848
1852
|
}
|
|
@@ -2230,8 +2234,12 @@ function resolveRules(req, isReq, isRes) {
|
|
|
2230
2234
|
var protos;
|
|
2231
2235
|
if (req.isPluginReq) {
|
|
2232
2236
|
protos = req._isProxyReq ? proxyProtocols : pluginProtocols;
|
|
2237
|
+
} else if (isRes) {
|
|
2238
|
+
protos = pureResProtocols;
|
|
2239
|
+
} else if (isReq) {
|
|
2240
|
+
protos = req._resolvedG ? reqProtosWithoutG : reqProtocols;
|
|
2233
2241
|
} else {
|
|
2234
|
-
protos =
|
|
2242
|
+
protos = req._resolvedG ? protocolsWithoutG : protocols;
|
|
2235
2243
|
}
|
|
2236
2244
|
req._inlineValues = vals;
|
|
2237
2245
|
protos.forEach(function (name) {
|
|
@@ -2377,6 +2385,10 @@ proto.resolvePipe = function (req) {
|
|
|
2377
2385
|
return req.isPluginReq ? null : resolveSingleRule.call(this, req, 'pipe');
|
|
2378
2386
|
};
|
|
2379
2387
|
|
|
2388
|
+
proto.getGRuleList = function (req) {
|
|
2389
|
+
return resolveSingleRule.call(this, req, 'G', true);
|
|
2390
|
+
};
|
|
2391
|
+
|
|
2380
2392
|
proto.resolvePac = function (req) {
|
|
2381
2393
|
return resolveSingleRule.call(this, req, 'pac');
|
|
2382
2394
|
};
|
package/lib/rules/util.js
CHANGED
|
@@ -487,6 +487,36 @@ if (config.persistentCapture && config.isEnableCapture) {
|
|
|
487
487
|
setEnableCapture(true);
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
exports.setDisabledCertFile = function(filename, disabled) {
|
|
491
|
+
var len = util.isString(filename) ? filename.length : 0;
|
|
492
|
+
if (!len || len > 100) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
var list = propertiesStorage.getProperty('disabledCertFiles');
|
|
496
|
+
if (!Array.isArray(list)) {
|
|
497
|
+
list = [];
|
|
498
|
+
}
|
|
499
|
+
var index = list.indexOf(filename);
|
|
500
|
+
if (disabled) {
|
|
501
|
+
if (index !== -1) {
|
|
502
|
+
list.splice(index, 1);
|
|
503
|
+
}
|
|
504
|
+
list.push(filename);
|
|
505
|
+
if (list.length > 256) {
|
|
506
|
+
list = list.slice(-256);
|
|
507
|
+
}
|
|
508
|
+
propertiesStorage.setProperty('disabledCertFiles', list);
|
|
509
|
+
} else if (index !== -1) {
|
|
510
|
+
list.splice(index, 1);
|
|
511
|
+
propertiesStorage.setProperty('disabledCertFiles', list);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
exports.isDisabledCertFile = function(filename) {
|
|
516
|
+
var list = propertiesStorage.getProperty('disabledCertFiles');
|
|
517
|
+
return Array.isArray(list) && list.indexOf(filename) !== -1;
|
|
518
|
+
};
|
|
519
|
+
|
|
490
520
|
exports.properties = {
|
|
491
521
|
setIPv6Only: function(checked) {
|
|
492
522
|
checked = !!checked;
|
package/lib/service/composer.js
CHANGED
|
@@ -176,7 +176,7 @@ function getReqRaw(options) {
|
|
|
176
176
|
function handleWebSocket(options, cb, count) {
|
|
177
177
|
count = getReqCount(count);
|
|
178
178
|
if (options.protocol === 'https:' || options.protocol === 'wss:') {
|
|
179
|
-
options.headers[
|
|
179
|
+
options.headers[common.HTTPS_FIELD] = 1;
|
|
180
180
|
}
|
|
181
181
|
var binary = !!options.headers['x-whistle-frame-binary'];
|
|
182
182
|
delete options.headers['x-whistle-frame-binary'];
|
|
@@ -234,7 +234,7 @@ function handleWebSocket(options, cb, count) {
|
|
|
234
234
|
function handleHttp(options, cb, count, reqId) {
|
|
235
235
|
count = getReqCount(count);
|
|
236
236
|
if (options.protocol === 'https:') {
|
|
237
|
-
options.headers[
|
|
237
|
+
options.headers[common.HTTPS_FIELD] = 1;
|
|
238
238
|
}
|
|
239
239
|
options.protocol = null;
|
|
240
240
|
options.hostname = null;
|
|
@@ -353,14 +353,14 @@ exports.handleRequest = function(req, res) {
|
|
|
353
353
|
var method = common.getMethod(req.body.method);
|
|
354
354
|
var isWebSocket = method === 'WEBSOCKET';
|
|
355
355
|
delete headers[config.WEBUI_HEAD];
|
|
356
|
-
headers[config.
|
|
356
|
+
headers[config.FROM_COM_HEADER] = '1';
|
|
357
357
|
if (req.body.enableProxyRules === false) {
|
|
358
358
|
headers[config.DISABLE_RULES_HEADER] = '1';
|
|
359
359
|
}
|
|
360
360
|
headers.host = options.host;
|
|
361
361
|
options.clientId = clientId;
|
|
362
|
-
headers[config.
|
|
363
|
-
headers[config.
|
|
362
|
+
headers[config.CLIENT_IP_HEADER] = req.headers[config.CLIENT_IP_HEADER] || '127.0.0.1';
|
|
363
|
+
headers[config.CLIENT_PORT_HEADER] = common.getClientPort(req, config);
|
|
364
364
|
options.method = method;
|
|
365
365
|
|
|
366
366
|
var isConn = common.isConnect(options);
|
package/lib/service/util.js
CHANGED
|
@@ -256,30 +256,16 @@ function parseJSON(str) {
|
|
|
256
256
|
|
|
257
257
|
exports.parseJSON = parseJSON;
|
|
258
258
|
|
|
259
|
-
function padding(num) {
|
|
260
|
-
return num < 10 ? '0' + num : num;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function paddingMS(ms) {
|
|
264
|
-
if (ms > 99) {
|
|
265
|
-
return ms;
|
|
266
|
-
}
|
|
267
|
-
if (ms > 9) {
|
|
268
|
-
return '0' + ms;
|
|
269
|
-
}
|
|
270
|
-
return '00' + ms;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
259
|
function formatDate() {
|
|
274
260
|
var date = new Date();
|
|
275
261
|
var result = [];
|
|
276
262
|
result.push(date.getFullYear());
|
|
277
|
-
result.push(
|
|
278
|
-
result.push(
|
|
279
|
-
result.push(
|
|
280
|
-
result.push(
|
|
281
|
-
result.push(
|
|
282
|
-
result.push(
|
|
263
|
+
result.push(common.padLeft(date.getMonth() + 1));
|
|
264
|
+
result.push(common.padLeft(date.getDate()));
|
|
265
|
+
result.push(common.padLeft(date.getHours()));
|
|
266
|
+
result.push(common.padLeft(date.getMinutes()));
|
|
267
|
+
result.push(common.padLeft(date.getSeconds()));
|
|
268
|
+
result.push(common.padLeft(date.getMilliseconds(), 3));
|
|
283
269
|
return result.join('');
|
|
284
270
|
}
|
|
285
271
|
|
|
@@ -331,7 +317,7 @@ function toISOString(time) {
|
|
|
331
317
|
time.toISOString().slice(0, -1) +
|
|
332
318
|
'0000' +
|
|
333
319
|
(offet >= 0 ? '+' : '-') +
|
|
334
|
-
|
|
320
|
+
common.padLeft(Math.abs(offet)) +
|
|
335
321
|
':00'
|
|
336
322
|
);
|
|
337
323
|
}
|