whistle 2.10.1 → 2.10.2
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 +44 -27
- package/bin/use.js +236 -101
- package/bin/util.js +10 -7
- package/biz/webui/cgi-bin/get-data.js +0 -5
- package/biz/webui/cgi-bin/init.js +0 -2
- package/biz/webui/htdocs/index.html +2 -2
- package/biz/webui/htdocs/js/index.js +50 -49
- package/biz/webui/lib/index.js +18 -3
- package/lib/config.js +3 -0
- package/lib/https/ca.js +8 -9
- package/lib/https/index.js +106 -112
- package/lib/index.js +1 -3
- package/lib/inspectors/log.js +4 -0
- package/lib/inspectors/weinre.js +7 -2
- package/lib/rules/index.js +0 -1
- package/lib/rules/protocols.js +3 -9
- package/lib/rules/rules.js +19 -19
- package/lib/{util/log-server.js → service/console-log.js} +37 -34
- package/lib/service/index.js +2 -4
- package/lib/service/service.js +52 -7
- package/lib/tunnel.js +2 -4
- package/lib/upgrade.js +1 -1
- package/lib/util/common.js +74 -10
- package/lib/util/index.js +24 -36
- package/package.json +1 -1
- package/biz/webui/cgi-bin/log/set.js +0 -7
- package/lib/util/parse-query.js +0 -35
package/lib/rules/rules.js
CHANGED
|
@@ -98,6 +98,7 @@ var FILE_PROTO_RE = /^x?((raw)?file|tpl|jsonp|dust):\/\//;
|
|
|
98
98
|
var NO_PROTO_RE = /[^\w!*|.-]/;
|
|
99
99
|
var SKIP_RE = /^skip:\/\//;
|
|
100
100
|
var SUB_VAR_RE = /\$\{RegExp\.\$([&\d])\}/g;
|
|
101
|
+
var TOOL_RE = /^(?:log|weinre):\/\//;
|
|
101
102
|
var mIndex = 0;
|
|
102
103
|
var mNow = Date.now();
|
|
103
104
|
var IS_JSON = Symbol('isJson');
|
|
@@ -799,18 +800,12 @@ function getValueFor(key, vals, file) {
|
|
|
799
800
|
return val;
|
|
800
801
|
}
|
|
801
802
|
|
|
802
|
-
function getRule(req, list, vals, index, isFilter, host) {
|
|
803
|
-
var rule = resolveRuleList(req, list, vals, index || 0, isFilter, null, host);
|
|
803
|
+
function getRule(req, list, vals, index, isFilter, host, isReq) {
|
|
804
|
+
var rule = resolveRuleList(req, list, vals, index || 0, isFilter, null, host, isReq);
|
|
804
805
|
resolveValue(rule, vals, req);
|
|
805
806
|
return rule;
|
|
806
807
|
}
|
|
807
808
|
|
|
808
|
-
function getRuleList(req, list, vals, isEnableProxy) {
|
|
809
|
-
return resolveRuleList(req, list, vals, isEnableProxy).map(function (rule) {
|
|
810
|
-
return resolveValue(rule, vals, req);
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
|
|
814
809
|
function resolveValue(rule, vals, req) {
|
|
815
810
|
if (!rule) {
|
|
816
811
|
return;
|
|
@@ -924,7 +919,7 @@ function checkInternal(req, rule) {
|
|
|
924
919
|
return props.internalOnly;
|
|
925
920
|
}
|
|
926
921
|
|
|
927
|
-
function resolveRuleList(req, list, vals, index, isFilter, isEnableProxy, host) {
|
|
922
|
+
function resolveRuleList(req, list, vals, index, isFilter, isEnableProxy, host, isReq) {
|
|
928
923
|
var curUrl = util.formatUrl(req.curUrl);
|
|
929
924
|
var notHttp = list.isRuleProto && curUrl[0] !== 'h';
|
|
930
925
|
//支持域名匹配
|
|
@@ -986,6 +981,9 @@ function resolveRuleList(req, list, vals, index, isFilter, isEnableProxy, host)
|
|
|
986
981
|
if (notHttp && protoMgr.isFileProxy(rule.matcher)) {
|
|
987
982
|
return false;
|
|
988
983
|
}
|
|
984
|
+
if (isReq && TOOL_RE.test(rule.matcher)) {
|
|
985
|
+
return true;
|
|
986
|
+
}
|
|
989
987
|
return (isFilter || !matchExcludeFilters(curUrl, rule, req)) && (host == null || util.checkProxyHost(rule, host));
|
|
990
988
|
};
|
|
991
989
|
|
|
@@ -1155,7 +1153,7 @@ function resolveProps(req, rules, vals, isIgnore) {
|
|
|
1155
1153
|
return result;
|
|
1156
1154
|
}
|
|
1157
1155
|
}
|
|
1158
|
-
return util.
|
|
1156
|
+
return util.parseRuleProps(list, result);
|
|
1159
1157
|
}
|
|
1160
1158
|
|
|
1161
1159
|
function parseWildcard(pattern, not) {
|
|
@@ -1967,7 +1965,7 @@ function matchFilter(url, filter, req) {
|
|
|
1967
1965
|
return false;
|
|
1968
1966
|
}
|
|
1969
1967
|
|
|
1970
|
-
function matchExcludeFilters(url, rule,
|
|
1968
|
+
function matchExcludeFilters(url, rule, req) {
|
|
1971
1969
|
var filters = rule.filters;
|
|
1972
1970
|
if (!filters) {
|
|
1973
1971
|
return;
|
|
@@ -1980,7 +1978,7 @@ function matchExcludeFilters(url, rule, options) {
|
|
|
1980
1978
|
hasIncludeFilter = hasIncludeFilter || filter.isInclude;
|
|
1981
1979
|
if (
|
|
1982
1980
|
(filter.isInclude ? !include : !exclude) &&
|
|
1983
|
-
matchFilter(url, filter,
|
|
1981
|
+
matchFilter(url, filter, req)
|
|
1984
1982
|
) {
|
|
1985
1983
|
if (filter.isInclude) {
|
|
1986
1984
|
include = true;
|
|
@@ -2249,7 +2247,7 @@ function resolveRules(req, isReq, isRes) {
|
|
|
2249
2247
|
name === 'rule' ||
|
|
2250
2248
|
name === 'plugin' ||
|
|
2251
2249
|
!filter[name]) &&
|
|
2252
|
-
(rule = self.getRule(req, rules[name], vals))
|
|
2250
|
+
(rule = self.getRule(req, rules[name], vals, null, null, null, isReq))
|
|
2253
2251
|
) {
|
|
2254
2252
|
_rules[name] = rule;
|
|
2255
2253
|
}
|
|
@@ -2283,15 +2281,17 @@ function resolveRules(req, isReq, isRes) {
|
|
|
2283
2281
|
return _rules;
|
|
2284
2282
|
}
|
|
2285
2283
|
|
|
2286
|
-
proto.getRule = function(req, list, vals, index, isFilter, host) {
|
|
2284
|
+
proto.getRule = function(req, list, vals, index, isFilter, host, isReq) {
|
|
2287
2285
|
if (!this._isGlobal || !req._disabledProxyRules) {
|
|
2288
|
-
return getRule(req, list, vals, index, isFilter, host);
|
|
2286
|
+
return getRule(req, list, vals, index, isFilter, host, isReq);
|
|
2289
2287
|
}
|
|
2290
2288
|
};
|
|
2291
2289
|
|
|
2292
2290
|
proto.getRuleList = function(req, list, vals, isEnableProxy) {
|
|
2293
2291
|
if (!this._isGlobal || !req._disabledProxyRules) {
|
|
2294
|
-
return
|
|
2292
|
+
return resolveRuleList(req, list, vals, null, false, isEnableProxy).map(function (rule) {
|
|
2293
|
+
return resolveValue(rule, vals, req);
|
|
2294
|
+
});
|
|
2295
2295
|
}
|
|
2296
2296
|
return [];
|
|
2297
2297
|
};
|
|
@@ -2341,8 +2341,8 @@ proto.resolveProxyProps = function (req) {
|
|
|
2341
2341
|
}
|
|
2342
2342
|
mergeRule(req.rules, enable, 'enable');
|
|
2343
2343
|
mergeRule(req.rules, disable, 'disable');
|
|
2344
|
-
enable = util.
|
|
2345
|
-
disable = util.
|
|
2344
|
+
enable = util.parseRuleProps(enable);
|
|
2345
|
+
disable = util.parseRuleProps(disable);
|
|
2346
2346
|
if (disable.clientId || disable.clientID || disable.clientid) {
|
|
2347
2347
|
req.disable.clientId = true;
|
|
2348
2348
|
}
|
|
@@ -2417,7 +2417,7 @@ proto.hasReqScript = function (req) {
|
|
|
2417
2417
|
: this.getRule(req, this._rules.rulesFile, this._values);
|
|
2418
2418
|
};
|
|
2419
2419
|
|
|
2420
|
-
proto.resolveProxy = function
|
|
2420
|
+
proto.resolveProxy = function (req, host) {
|
|
2421
2421
|
var proxy = this.getRule(req, this._rules.proxy, this._values, null, null, host);
|
|
2422
2422
|
var matcher = proxy && proxy.matcher;
|
|
2423
2423
|
var name = matcher && matcher.substring(0, matcher.indexOf(':'));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var MAX_LENGTH = 800;
|
|
2
2
|
var MIN_LENGTH = 720;
|
|
3
|
-
var SIZE = 1024 *
|
|
3
|
+
var SIZE = 1024 * 512;
|
|
4
4
|
var COUNT = 100;
|
|
5
5
|
var logIndex = 0;
|
|
6
6
|
var logs = [];
|
|
@@ -45,40 +45,43 @@ function getLogs(startTime, count, logId) {
|
|
|
45
45
|
return sliceLogs(0, count, logId);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
function getLogIndex() {
|
|
49
|
+
++logIndex;
|
|
50
|
+
if (logIndex > 999999) {
|
|
51
|
+
logIndex = 0;
|
|
52
|
+
}
|
|
53
|
+
return logIndex;
|
|
54
|
+
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
exports.addLog = function set(log) {
|
|
57
|
+
if (!log) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var now = Date.now();
|
|
62
|
+
var text = log.text;
|
|
63
|
+
if (text == null) {
|
|
64
|
+
text = '';
|
|
65
|
+
} else if (typeof text != 'string') {
|
|
66
|
+
text += '';
|
|
67
|
+
}
|
|
68
|
+
var overflow = text.length - SIZE;
|
|
69
|
+
logs.push({
|
|
70
|
+
id: now + '-' + getLogIndex(),
|
|
71
|
+
logId: log.id,
|
|
72
|
+
date: (log.t && parseInt(log.t, 10)) || now,
|
|
73
|
+
level: LEVEL_RE.test(log.level)
|
|
67
74
|
? log.level
|
|
68
75
|
: 'info',
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
proxy.getLatestId = function () {
|
|
81
|
-
var last = logs[logs.length - 1];
|
|
82
|
-
return last && last.id;
|
|
83
|
-
};
|
|
76
|
+
text: overflow > 9 ? text.substring(0, SIZE) + '...(' + overflow + ')' : text
|
|
77
|
+
});
|
|
78
|
+
var len = logs.length;
|
|
79
|
+
if (len > MAX_LENGTH) {
|
|
80
|
+
logs = logs.slice(len - MIN_LENGTH, len);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
exports.getLogs = getLogs;
|
|
84
|
+
exports.getLatestId = function () {
|
|
85
|
+
var last = logs[logs.length - 1];
|
|
86
|
+
return last && last.id;
|
|
84
87
|
};
|
package/lib/service/index.js
CHANGED
|
@@ -170,9 +170,7 @@ var saveData = function(type, data) {
|
|
|
170
170
|
method: 'POST',
|
|
171
171
|
url: 'http://127.0.0.1:' + curOptions.port + '/cgi-bin/service/save',
|
|
172
172
|
strictMode: true,
|
|
173
|
-
headers: {
|
|
174
|
-
'content-type': 'application/json'
|
|
175
|
-
},
|
|
173
|
+
headers: { 'content-type': 'application/json' },
|
|
176
174
|
body: body
|
|
177
175
|
}, function (err) {
|
|
178
176
|
if (err) {
|
|
@@ -213,7 +211,7 @@ function sendData() {
|
|
|
213
211
|
});
|
|
214
212
|
}
|
|
215
213
|
|
|
216
|
-
process.
|
|
214
|
+
process.on('whistleStarted', sendData);
|
|
217
215
|
|
|
218
216
|
module.exports = loadService;
|
|
219
217
|
|
package/lib/service/service.js
CHANGED
|
@@ -16,6 +16,7 @@ var composer = require('./composer');
|
|
|
16
16
|
var handleComposeData = require('./compose-data');
|
|
17
17
|
var Limiter = require('async-limiter');
|
|
18
18
|
var common = require('../util/common');
|
|
19
|
+
var logger = require('./console-log');
|
|
19
20
|
|
|
20
21
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
|
|
21
22
|
|
|
@@ -26,7 +27,7 @@ var forwardRequest = dataCenter.forwardRequest;
|
|
|
26
27
|
|
|
27
28
|
var INSTALL_SCRIPT = path.join(__dirname, 'install.js');
|
|
28
29
|
var installChild;
|
|
29
|
-
|
|
30
|
+
var LOG_RE = /^(\d+)\r(fatal|error|warn|info|debug|log)\r([^\s]*)\r/;
|
|
30
31
|
var TEMP_PLUGINS_PATH = path.join(common.getWhistlePath(), '.temp_plugins');
|
|
31
32
|
var SESSIONS_FILE_RE = /\.(txt|json|saz)$/i;
|
|
32
33
|
var limiter = new Limiter({ concurrency: 10 });
|
|
@@ -37,10 +38,8 @@ var LIMIT_SIZE = 1024 * 1024 * 128;
|
|
|
37
38
|
var MAX_TEMP_SIZE = 1024 * 1024 * 12;
|
|
38
39
|
var MAX_PLUGIN_SIZE = MAX_TEMP_SIZE;
|
|
39
40
|
var MAX_TEMP_PLUGINS_AGE = 1000 * 60 * 10; // 10 minutes
|
|
40
|
-
var TEMP_FILE_RE = /^[\da-f]{64}$/;
|
|
41
41
|
var CR = '\r';
|
|
42
42
|
var jsonParser = bodyParser.json({ limit: LIMIT_SIZE });
|
|
43
|
-
var urlencodedParser = bodyParser.urlencoded({ extended: true, limit: '1mb'});
|
|
44
43
|
var PLUGIN_SEP = /\s*,\s*/;
|
|
45
44
|
var config;
|
|
46
45
|
var curWhistleId;
|
|
@@ -67,6 +66,19 @@ var ensureTempPluginsDir = function() {
|
|
|
67
66
|
|
|
68
67
|
ensureTempPluginsDir();
|
|
69
68
|
|
|
69
|
+
function parseLog(log) {
|
|
70
|
+
if (!log || typeof log !== 'string') {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
var match = LOG_RE.exec(log);
|
|
74
|
+
return match && {
|
|
75
|
+
t: match[1],
|
|
76
|
+
level: match[2],
|
|
77
|
+
id: match[3],
|
|
78
|
+
text: log.substring(match[0].length)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
process.on('data', function(data) {
|
|
71
83
|
if (data) {
|
|
72
84
|
if (data.type === 'whistleId') {
|
|
@@ -155,7 +167,7 @@ function getTempFiles(list, cb) {
|
|
|
155
167
|
}
|
|
156
168
|
};
|
|
157
169
|
list = list.forEach(function(filename) {
|
|
158
|
-
if (!
|
|
170
|
+
if (!common.isTempFile(filename)) {
|
|
159
171
|
return execCb();
|
|
160
172
|
}
|
|
161
173
|
filename = path.join(TEMP_FILES_PATH, filename);
|
|
@@ -336,7 +348,7 @@ function sessionsHandler() {
|
|
|
336
348
|
} catch (e) {}
|
|
337
349
|
});
|
|
338
350
|
});
|
|
339
|
-
app.post('/cgi-bin/plugins/install',
|
|
351
|
+
app.post('/cgi-bin/plugins/install', bodyParser.urlencoded({ extended: true, limit: '1mb'}), function(req, res) {
|
|
340
352
|
var plugins = req.body.plugins;
|
|
341
353
|
var clientId = req.body.clientId;
|
|
342
354
|
plugins = common.isString(plugins) ? plugins.trim().split(PLUGIN_SEP) : null;
|
|
@@ -444,7 +456,7 @@ function sessionsHandler() {
|
|
|
444
456
|
});
|
|
445
457
|
}
|
|
446
458
|
var filename = req.query.filename;
|
|
447
|
-
if (
|
|
459
|
+
if (common.isTempFile(filename)) {
|
|
448
460
|
filename = path.join(TEMP_FILES_PATH, filename);
|
|
449
461
|
}
|
|
450
462
|
getFile(filename, function(em, data) {
|
|
@@ -491,8 +503,12 @@ function sessionsHandler() {
|
|
|
491
503
|
}
|
|
492
504
|
}
|
|
493
505
|
);
|
|
506
|
+
app.use('/cgi-bin/log/set', function(req, _, next) {
|
|
507
|
+
req.headers['content-type'] = 'application/json';
|
|
508
|
+
next();
|
|
509
|
+
});
|
|
494
510
|
app.use(bodyParser.urlencoded({ extended: true, limit: LIMIT_SIZE }));
|
|
495
|
-
app.use(
|
|
511
|
+
app.use(jsonParser);
|
|
496
512
|
app.use('/cgi-bin/sessions/export', function (req, res) {
|
|
497
513
|
var body = req.body;
|
|
498
514
|
var type = body.exportFileType;
|
|
@@ -509,6 +525,35 @@ function sessionsHandler() {
|
|
|
509
525
|
download(body);
|
|
510
526
|
});
|
|
511
527
|
});
|
|
528
|
+
|
|
529
|
+
app.use('/cgi-bin/log/set', function(req, res) {
|
|
530
|
+
res.setHeader('content-type', 'image/png');
|
|
531
|
+
if (req.method === 'POST') {
|
|
532
|
+
var list = req.body.list;
|
|
533
|
+
if (Array.isArray(list)) {
|
|
534
|
+
var len = Math.min(list.length, 20);
|
|
535
|
+
for (var i = 0; i < len; i++) {
|
|
536
|
+
logger.addLog(parseLog(list[i]));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
} else {
|
|
540
|
+
logger.addLog(req.query);
|
|
541
|
+
}
|
|
542
|
+
res.end();
|
|
543
|
+
});
|
|
544
|
+
app.use('/cgi-bin/log/get', function(req, res) {
|
|
545
|
+
var query = req.query;
|
|
546
|
+
var startLogTime = query.startLogTime;
|
|
547
|
+
var init = startLogTime == -4;
|
|
548
|
+
var stopRecordConsole = startLogTime == -3;
|
|
549
|
+
var curLogId = logger.getLatestId();
|
|
550
|
+
common.sendGzip(req, res, {
|
|
551
|
+
ec: 0,
|
|
552
|
+
log: init || stopRecordConsole ? [] : logger.getLogs(startLogTime, query.count, query.logId),
|
|
553
|
+
curLogId: stopRecordConsole ? undefined : curLogId,
|
|
554
|
+
lastLogId: init ? (curLogId || -2) : (stopRecordConsole ? curLogId : undefined)
|
|
555
|
+
});
|
|
556
|
+
});
|
|
512
557
|
return app;
|
|
513
558
|
}
|
|
514
559
|
|
package/lib/tunnel.js
CHANGED
|
@@ -47,8 +47,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
47
47
|
var headers = req.headers;
|
|
48
48
|
if (headers[config.WEBUI_HEAD]) {
|
|
49
49
|
delete headers[config.WEBUI_HEAD];
|
|
50
|
-
reqSocket.destroy();
|
|
51
|
-
return;
|
|
50
|
+
return reqSocket.destroy();
|
|
52
51
|
}
|
|
53
52
|
req.fromHttpServer = reqSocket.fromHttpServer = fromHttpServer;
|
|
54
53
|
req.fromHttpsServer = reqSocket.fromHttpsServer = fromHttpsServer;
|
|
@@ -83,8 +82,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
83
82
|
var clientInfo = util.parseClientInfo(req);
|
|
84
83
|
reqSocket._disabledProxyRules = req._disabledProxyRules;
|
|
85
84
|
reqSocket.clientIp = req.clientIp = util.getClientIp(req, clientInfo[0]);
|
|
86
|
-
reqSocket.clientPort = req.clientPort =
|
|
87
|
-
clientInfo[1] || util.getClientPort(req);
|
|
85
|
+
reqSocket.clientPort = req.clientPort = clientInfo[1] || util.getClientPort(req);
|
|
88
86
|
req._remoteAddr = clientInfo[2] || util.getRemoteAddr(req);
|
|
89
87
|
req._remotePort = clientInfo[3] || util.getRemotePort(req);
|
|
90
88
|
delete headers[config.CLIENT_PORT_HEADER];
|
package/lib/upgrade.js
CHANGED
|
@@ -105,7 +105,7 @@ function upgradeHandler(req, socket) {
|
|
|
105
105
|
util.addTunnelData(socket, headers);
|
|
106
106
|
socket._clientId = util.getComposerClientId(headers);
|
|
107
107
|
var getBuffer = function (method, newHeaders, path) {
|
|
108
|
-
var rawData = (method || 'GET') + ' ' + (path || socket.url || req.url) + '
|
|
108
|
+
var rawData = (method || 'GET') + ' ' + (path || socket.url || req.url) + ' HTTP/1.1';
|
|
109
109
|
newHeaders = formatHeaders(newHeaders || headers, req.rawHeaders);
|
|
110
110
|
if (newHeaders = getRawHeaders(newHeaders)) {
|
|
111
111
|
rawData += '\r\n' + newHeaders;
|
package/lib/util/common.js
CHANGED
|
@@ -67,6 +67,73 @@ var PATH_SEP_RE = /[\\/]/;
|
|
|
67
67
|
var CUR_PATH_RE = /^\.[\\/]/;
|
|
68
68
|
var CLIENT_PORT_HEADER = 'x-whistle-client-port';
|
|
69
69
|
var ALLOW_ACK = 'x-whistle-allow-tunnel-ack';
|
|
70
|
+
var PLUS_RE = /\+/g;
|
|
71
|
+
var TOKEN = '\r\u0000\n\u0003\r';
|
|
72
|
+
var PROP_SEP_RE = /(\\*)([|&]|\\[stnrfv])/g;
|
|
73
|
+
var TEMP_FILE_RE = /^[\da-f]{64}$/;
|
|
74
|
+
|
|
75
|
+
exports.isTempFile = function(str) {
|
|
76
|
+
return TEMP_FILE_RE.test(str);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
var PROPS_CHAR = {
|
|
80
|
+
s: ' ',
|
|
81
|
+
t: '\t',
|
|
82
|
+
n: '\n',
|
|
83
|
+
r: '\r',
|
|
84
|
+
f: '\f',
|
|
85
|
+
v: '\v'
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
function replaceToken(s, val) {
|
|
89
|
+
return s.split(TOKEN).join(val);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
exports.parseProps = function(str) {
|
|
93
|
+
return str.replace(PROP_SEP_RE, function(_, slash, val) {
|
|
94
|
+
var isChar = val.length > 1;
|
|
95
|
+
if (isChar) {
|
|
96
|
+
slash += '/';
|
|
97
|
+
val = val.substring(1);
|
|
98
|
+
} else if (!slash) {
|
|
99
|
+
return TOKEN;
|
|
100
|
+
}
|
|
101
|
+
var len = slash.length;
|
|
102
|
+
slash = slash.substring(0, Math.floor(len / 2));
|
|
103
|
+
if (isChar) {
|
|
104
|
+
return slash + (len % 2 ? PROPS_CHAR[val] : val);
|
|
105
|
+
}
|
|
106
|
+
return slash + (len % 2 ? val : TOKEN);
|
|
107
|
+
}).split(TOKEN);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
var decoder = {
|
|
111
|
+
decodeURIComponent: function (s) {
|
|
112
|
+
s = replaceToken(s, '+');
|
|
113
|
+
return qs.unescape(s);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var rawDecoder = {
|
|
117
|
+
decodeURIComponent: function (s) {
|
|
118
|
+
return replaceToken(s, '+');
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var rawDecoder2 = {
|
|
122
|
+
decodeURIComponent: function (s) {
|
|
123
|
+
return s;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
exports.parseQuery = function (str, sep, eq, escape) {
|
|
128
|
+
try {
|
|
129
|
+
if (str.indexOf('+') === -1 || str.indexOf(TOKEN) !== -1) {
|
|
130
|
+
return qs.parse(str, sep, eq, escape ? rawDecoder2 : undefined);
|
|
131
|
+
}
|
|
132
|
+
str = str.replace(PLUS_RE, TOKEN);
|
|
133
|
+
return qs.parse(str, sep, eq, escape ? rawDecoder : decoder);
|
|
134
|
+
} catch (e) {}
|
|
135
|
+
return '';
|
|
136
|
+
};
|
|
70
137
|
|
|
71
138
|
exports.ALLOW_ACK = ALLOW_ACK;
|
|
72
139
|
exports.CONN_TIMEOUT = CONN_TIMEOUT;
|
|
@@ -894,7 +961,6 @@ var DIG_RE = /^([+-]?)([1-9]\d{0,15})$/;
|
|
|
894
961
|
var NUM_RE = /^(?:0|[1-9]\d*)$/;
|
|
895
962
|
var ARR_RE = /\[(0|[1-8]\d{0,15}|9\d{0,14})\]$/;
|
|
896
963
|
var DOT_RE = /(\\+)\./g;
|
|
897
|
-
var CR_RE = /\r/g;
|
|
898
964
|
|
|
899
965
|
function isString(str) {
|
|
900
966
|
return str && typeof str === 'string';
|
|
@@ -963,12 +1029,6 @@ function parseKey(key) {
|
|
|
963
1029
|
return list;
|
|
964
1030
|
}
|
|
965
1031
|
|
|
966
|
-
function replaceDot(_, slash) {
|
|
967
|
-
var len = slash.length;
|
|
968
|
-
slash = slash.substring(0, Math.floor(len / 2));
|
|
969
|
-
return slash + (len % 2 ? '\r' : '.');
|
|
970
|
-
}
|
|
971
|
-
|
|
972
1032
|
function parseKeys(key) {
|
|
973
1033
|
if (!isString(key)) {
|
|
974
1034
|
return key;
|
|
@@ -977,13 +1037,17 @@ function parseKeys(key) {
|
|
|
977
1037
|
if (key.indexOf('.') === -1) {
|
|
978
1038
|
return parseKey(key);
|
|
979
1039
|
}
|
|
980
|
-
key = key.replace(DOT_RE,
|
|
1040
|
+
key = key.replace(DOT_RE, function (_, slash) {
|
|
1041
|
+
var len = slash.length;
|
|
1042
|
+
slash = slash.substring(0, Math.floor(len / 2));
|
|
1043
|
+
return slash + (len % 2 ? TOKEN : '.');
|
|
1044
|
+
});
|
|
981
1045
|
if (key.indexOf('.') === -1) {
|
|
982
|
-
return parseKey(key
|
|
1046
|
+
return parseKey(replaceToken(key, '.'));
|
|
983
1047
|
}
|
|
984
1048
|
var result = [];
|
|
985
1049
|
key.split('.').forEach(function(k) {
|
|
986
|
-
k = parseKey(k.trim()
|
|
1050
|
+
k = parseKey(replaceToken(k.trim(), '.'));
|
|
987
1051
|
if (Array.isArray(k)) {
|
|
988
1052
|
result = result.concat(k);
|
|
989
1053
|
} else {
|
package/lib/util/index.js
CHANGED
|
@@ -15,20 +15,21 @@ var dns = require('dns');
|
|
|
15
15
|
var mime = require('mime');
|
|
16
16
|
var PipeStream = require('pipestream');
|
|
17
17
|
var protoMgr = require('../rules/protocols');
|
|
18
|
-
var protocols = protoMgr.protocols;
|
|
19
18
|
var logger = require('./logger');
|
|
20
19
|
var config = require('../config');
|
|
21
20
|
var isUtf8 = require('./is-utf8');
|
|
22
21
|
var fileMgr = require('./file-mgr');
|
|
23
22
|
var httpMgr = require('./http-mgr');
|
|
24
23
|
var ReplacePatternTransform = require('./replace-pattern-transform');
|
|
25
|
-
var parseQuery = require('./parse-query');
|
|
26
24
|
var common = require('./common');
|
|
27
25
|
var proc = require('./process');
|
|
28
26
|
var parseUrl = require('./parse-url');
|
|
29
27
|
var h2Consts = config.enableH2 ? require('http2').constants : {};
|
|
30
28
|
|
|
29
|
+
var protocols = protoMgr.protocols;
|
|
30
|
+
var resProtocols = protoMgr.resProtocols;
|
|
31
31
|
var uid = config.uid;
|
|
32
|
+
var parseQuery = common.parseQuery;
|
|
32
33
|
var supportsBr = common.supportsBr;
|
|
33
34
|
var isLocalIp = common.isLocalIp;
|
|
34
35
|
var getStat = common.getStat;
|
|
@@ -1855,23 +1856,21 @@ function joinPath(root, dir) {
|
|
|
1855
1856
|
|
|
1856
1857
|
exports.joinPath = joinPath;
|
|
1857
1858
|
|
|
1858
|
-
function
|
|
1859
|
+
function parseRuleProps(list, result) {
|
|
1859
1860
|
result = result || {};
|
|
1860
1861
|
if (list) {
|
|
1861
|
-
list
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
.split(SEP_RE)
|
|
1865
|
-
.forEach(function (action) {
|
|
1866
|
-
if (action) {
|
|
1862
|
+
list.forEach(function(rule) {
|
|
1863
|
+
if (rule = getMatcherValue(rule)) {
|
|
1864
|
+
common.parseProps(rule).forEach(function (action) {
|
|
1867
1865
|
result[action] = true;
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1870
1869
|
}
|
|
1871
1870
|
return result;
|
|
1872
1871
|
}
|
|
1873
1872
|
|
|
1874
|
-
exports.
|
|
1873
|
+
exports.parseRuleProps = parseRuleProps;
|
|
1875
1874
|
|
|
1876
1875
|
exports.parseLineProps = function (str) {
|
|
1877
1876
|
str = str && removeProtocol(str, true);
|
|
@@ -1998,17 +1997,7 @@ exports.checkSkip = function(skip, rule, curUrl) {
|
|
|
1998
1997
|
};
|
|
1999
1998
|
|
|
2000
1999
|
function resolveRuleProps(rule, result) {
|
|
2001
|
-
|
|
2002
|
-
if (rule) {
|
|
2003
|
-
rule.list.forEach(function (rule) {
|
|
2004
|
-
getMatcherValue(rule)
|
|
2005
|
-
.split(SEP_RE)
|
|
2006
|
-
.forEach(function (action) {
|
|
2007
|
-
result[action] = true;
|
|
2008
|
-
});
|
|
2009
|
-
});
|
|
2010
|
-
}
|
|
2011
|
-
return result;
|
|
2000
|
+
return parseRuleProps(rule && rule.list, result);
|
|
2012
2001
|
}
|
|
2013
2002
|
|
|
2014
2003
|
var PLUGIN_RE = /^(?:plugin|whistle)\.[a-z\d_\-]+$/;
|
|
@@ -2089,7 +2078,7 @@ function ignoreRules(rules, ignore, isResRules) {
|
|
|
2089
2078
|
if (name === 'filter' || name === 'ignore' || exclude[name]) {
|
|
2090
2079
|
return;
|
|
2091
2080
|
}
|
|
2092
|
-
if (!isResRules ||
|
|
2081
|
+
if (!isResRules || resProtocols.indexOf(name) !== -1) {
|
|
2093
2082
|
if (
|
|
2094
2083
|
ignorePlugins(rules, name, exclude) ||
|
|
2095
2084
|
ignoreProxy(rules, name, exclude) ||
|
|
@@ -2191,7 +2180,7 @@ function mergeRules(req, add, isResRules) {
|
|
|
2191
2180
|
};
|
|
2192
2181
|
if (origAdd) {
|
|
2193
2182
|
if (isResRules) {
|
|
2194
|
-
|
|
2183
|
+
resProtocols.forEach(merge);
|
|
2195
2184
|
} else {
|
|
2196
2185
|
Object.keys(origAdd).forEach(merge);
|
|
2197
2186
|
}
|
|
@@ -2680,12 +2669,12 @@ var REQ_HEADER_RE = /^req\.?H(?:eaders?)?\.(.+)$/i;
|
|
|
2680
2669
|
var RES_HEADER_RE = /^res\.?H(?:eaders?)?\.(.+)$/i;
|
|
2681
2670
|
var TRAILER_RE = /trailer\.(.+)$/;
|
|
2682
2671
|
var HEADER_RE = /^headers\.(.+)$/;
|
|
2683
|
-
var REQ_COOKIE_RE = /^req\.?C(?:ookies?)?\.(
|
|
2684
|
-
var RES_COOKIE_RE = /^res\.?C(?:ookies?)?\.(
|
|
2685
|
-
var REQ_BODY_RE = /^req\.?B(?:ody?)?\.(
|
|
2686
|
-
var RES_BODY_RE = /^res\.?B(?:ody?)?\.(
|
|
2687
|
-
var COOKIE_RE = /^cookies?\.(
|
|
2688
|
-
var QUERY_RE = /^(?:query|params|url\.?Params?)\.(
|
|
2672
|
+
var REQ_COOKIE_RE = /^req\.?C(?:ookies?)?\.([\s\S]+)$/i;
|
|
2673
|
+
var RES_COOKIE_RE = /^res\.?C(?:ookies?)?\.([\s\S]+)$/i;
|
|
2674
|
+
var REQ_BODY_RE = /^req\.?B(?:ody?)?\.([\s\S]+)$/i;
|
|
2675
|
+
var RES_BODY_RE = /^res\.?B(?:ody?)?\.([\s\S]+)$/i;
|
|
2676
|
+
var COOKIE_RE = /^cookies?\.([\s\S]+)$/i;
|
|
2677
|
+
var QUERY_RE = /^(?:query|params|url\.?Params?)\.([\s\S]+)$/i;
|
|
2689
2678
|
var QUERY_STRING_RE = /^(?:query|params|url\.?Params?)$/i;
|
|
2690
2679
|
var PATH_INDEX_RE = /^pathname(?:\.?(-?\d+|first|last))?$/i;
|
|
2691
2680
|
|
|
@@ -2766,12 +2755,11 @@ exports.parseDelResBody = function(req) {
|
|
|
2766
2755
|
|
|
2767
2756
|
exports.deleteProps = function(obj, keys) {
|
|
2768
2757
|
keys = obj && keys && Object.keys(keys);
|
|
2769
|
-
if (
|
|
2770
|
-
|
|
2758
|
+
if (keys && keys.length) {
|
|
2759
|
+
keys.forEach(function(key) {
|
|
2760
|
+
common.deleteProps(obj, key);
|
|
2761
|
+
});
|
|
2771
2762
|
}
|
|
2772
|
-
keys.forEach(function(key) {
|
|
2773
|
-
common.deleteProps(obj, key);
|
|
2774
|
-
});
|
|
2775
2763
|
};
|
|
2776
2764
|
|
|
2777
2765
|
function getDomain(req) {
|
package/package.json
CHANGED
package/lib/util/parse-query.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
var qs = require('querystring');
|
|
2
|
-
|
|
3
|
-
var TOKEN_RE = /\r\u0000\n\u0003\r/g;
|
|
4
|
-
var PLUS_RE = /\+/g;
|
|
5
|
-
var TOKEN = '\r\u0000\n\u0003\r';
|
|
6
|
-
|
|
7
|
-
var decoder = {
|
|
8
|
-
decodeURIComponent: function (s) {
|
|
9
|
-
s = s.replace(TOKEN_RE, '+');
|
|
10
|
-
return qs.unescape(s);
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
var rawDecoder = {
|
|
14
|
-
decodeURIComponent: function (s) {
|
|
15
|
-
return s.replace(TOKEN_RE, '+');
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
var rawDecoder2 = {
|
|
19
|
-
decodeURIComponent: function (s) {
|
|
20
|
-
return s;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
function parse(str, sep, eq, escape) {
|
|
25
|
-
try {
|
|
26
|
-
if (str.indexOf('+') === -1 || str.indexOf(TOKEN) !== -1) {
|
|
27
|
-
return qs.parse(str, sep, eq, escape ? rawDecoder2 : undefined);
|
|
28
|
-
}
|
|
29
|
-
str = str.replace(PLUS_RE, TOKEN);
|
|
30
|
-
return qs.parse(str, sep, eq, escape ? rawDecoder : decoder);
|
|
31
|
-
} catch (e) {}
|
|
32
|
-
return '';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
module.exports = parse;
|