whistle 2.10.3 → 2.10.5
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/menu.html +0 -1
- package/assets/modal.html +0 -1
- package/assets/tab.html +0 -1
- package/bin/proxy.js +2 -2
- package/biz/webui/cgi-bin/add-rules-values.js +1 -1
- package/biz/webui/cgi-bin/check-update.js +0 -1
- package/biz/webui/cgi-bin/do-not-show-again.js +1 -1
- package/biz/webui/cgi-bin/enable-http2.js +1 -1
- package/biz/webui/cgi-bin/get-matched-rules.js +14 -0
- package/biz/webui/cgi-bin/hide-https-connects.js +1 -1
- package/biz/webui/cgi-bin/intercept-https-connects.js +1 -1
- package/biz/webui/cgi-bin/plugins/disable-all-plugins.js +1 -1
- package/biz/webui/cgi-bin/reset-local-address.js +1 -1
- package/biz/webui/cgi-bin/rules/allow-multiple-choice.js +1 -1
- package/biz/webui/cgi-bin/rules/clear-dns-cache.js +1 -1
- package/biz/webui/cgi-bin/rules/disable-all-rules.js +1 -1
- package/biz/webui/cgi-bin/rules/disable-default.js +1 -1
- package/biz/webui/cgi-bin/rules/enable-back-rules-first.js +1 -1
- package/biz/webui/cgi-bin/rules/enable-default.js +1 -1
- package/biz/webui/cgi-bin/rules/move-to.js +1 -1
- package/biz/webui/cgi-bin/rules/remove.js +1 -1
- package/biz/webui/cgi-bin/rules/rename.js +1 -1
- package/biz/webui/cgi-bin/rules/select.js +1 -1
- package/biz/webui/cgi-bin/rules/set-sys-hosts.js +1 -1
- package/biz/webui/cgi-bin/rules/unselect.js +1 -1
- package/biz/webui/cgi-bin/util.js +0 -1
- package/biz/webui/cgi-bin/values/move-to.js +1 -1
- package/biz/webui/cgi-bin/values/remove.js +1 -1
- package/biz/webui/cgi-bin/values/rename.js +1 -1
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +52 -54
- package/lib/config.js +1 -0
- package/lib/https/index.js +1 -0
- package/lib/inspectors/data.js +2 -1
- package/lib/rules/rules.js +5 -5
- package/lib/service/composer.js +77 -35
- package/lib/tunnel.js +3 -0
- package/lib/upgrade.js +1 -0
- package/lib/util/common.js +11 -1
- package/lib/util/data-server.js +10 -0
- package/lib/util/index.js +14 -15
- package/package.json +2 -2
package/lib/config.js
CHANGED
|
@@ -91,6 +91,7 @@ config.WEBUI_HEAD = 'x-forwarded-from-whistle-' + uid;
|
|
|
91
91
|
config.RES_RULES_HEAD = 'x-whistle-res-rules-' + uid;
|
|
92
92
|
config.COMPOSER_CLIENT_ID_HEADER = 'x-whistle-client-id-' + uid;
|
|
93
93
|
config.FROM_COM_HEADER = 'x-whistle-composer-' + uid;
|
|
94
|
+
config.TEST_HEADER = 'x-whistle-test-' + uid;
|
|
94
95
|
config.PLUGIN_HOOKS = {
|
|
95
96
|
SNI: 'sni-' + uid,
|
|
96
97
|
AUTH: 'auth-' + uid,
|
package/lib/https/index.js
CHANGED
package/lib/inspectors/data.js
CHANGED
|
@@ -158,6 +158,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
158
158
|
h2Id: req._alpn,
|
|
159
159
|
fc: req.fromComposer ? 1 : undefined,
|
|
160
160
|
isPR: req.isPluginReq ? 1 : undefined,
|
|
161
|
+
testId: req._testId,
|
|
161
162
|
_clientId: req._clientId,
|
|
162
163
|
startTime: now,
|
|
163
164
|
ttfb: getTTFB(),
|
|
@@ -417,7 +418,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
417
418
|
req.once('dest', function (_req) {
|
|
418
419
|
_req.once('finish', function () {
|
|
419
420
|
if (!requestTime) {
|
|
420
|
-
setRequestTime(
|
|
421
|
+
setRequestTime(Date.now());
|
|
421
422
|
}
|
|
422
423
|
});
|
|
423
424
|
setReqStatus();
|
package/lib/rules/rules.js
CHANGED
|
@@ -7,6 +7,7 @@ var rulesUtil = require('./util');
|
|
|
7
7
|
var lookup = require('./dns');
|
|
8
8
|
var protoMgr = require('./protocols');
|
|
9
9
|
var config = require('../config');
|
|
10
|
+
var common = require('../util/common');
|
|
10
11
|
|
|
11
12
|
var rules = rulesUtil.rules;
|
|
12
13
|
var values = rulesUtil.values;
|
|
@@ -68,7 +69,6 @@ var NON_STAR_RE = /[^*]/;
|
|
|
68
69
|
var DOMAIN_STAR_RE = /([*~]+)(\\.)?/g;
|
|
69
70
|
var STAR_RE = /\*+/g;
|
|
70
71
|
var PORT_PATTERN_RE = /^!?:\d{1,5}$/;
|
|
71
|
-
var COMMENT_RE = /#[^\r\n]*/g;
|
|
72
72
|
var TPL_RE = /^((?:[\w.-]+:)?\/\/)?(`.*`)$/;
|
|
73
73
|
// url: protocol, host, port, hostname, search, query, pathname, path, href, query.key
|
|
74
74
|
// req|res: ip, method, statusCode, headers?.key, cookies?.key
|
|
@@ -101,6 +101,7 @@ var TOOL_RE = /^(?:log|weinre):\/\//;
|
|
|
101
101
|
var mIndex = 0;
|
|
102
102
|
var mNow = Date.now();
|
|
103
103
|
var IS_JSON = Symbol('isJson');
|
|
104
|
+
var removeComment = common.removeComment;
|
|
104
105
|
|
|
105
106
|
function getMFlag() {
|
|
106
107
|
if (mIndex === Number.MAX_SAFE_INTEGER) {
|
|
@@ -110,10 +111,6 @@ function getMFlag() {
|
|
|
110
111
|
return mNow + '-' + (mIndex++);
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
function removeComment(text) {
|
|
114
|
-
return text.replace(COMMENT_RE, '').trim();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
114
|
function domainToRegExp(all, star, dot) {
|
|
118
115
|
var len = star.length;
|
|
119
116
|
var result = len > 1 ? '([^/?]*)' : '([^/?.]*)';
|
|
@@ -1838,6 +1835,9 @@ function matchFilter(url, filter, req) {
|
|
|
1838
1835
|
if (filter.from === 'tunnel') {
|
|
1839
1836
|
return filter.not ? !req.fromTunnel : req.fromTunnel;
|
|
1840
1837
|
}
|
|
1838
|
+
if (filter.from === 'test') {
|
|
1839
|
+
return filter.not ? !req._testId : req._testId;
|
|
1840
|
+
}
|
|
1841
1841
|
if (filter.from === 'composer') {
|
|
1842
1842
|
return filter.not ? !req.fromComposer : req.fromComposer;
|
|
1843
1843
|
}
|
package/lib/service/composer.js
CHANGED
|
@@ -29,6 +29,7 @@ var MAX_BODY_LEN = 260 * 1024;
|
|
|
29
29
|
var MAX_BASE64_LEN = 360 * 1024;
|
|
30
30
|
var MAX_METHOD_LEN = 64;
|
|
31
31
|
var LEN_HEADER = 'content-length';
|
|
32
|
+
var testIndex = 0;
|
|
32
33
|
|
|
33
34
|
var composerTimer;
|
|
34
35
|
function saveComposerHistory() {
|
|
@@ -125,7 +126,24 @@ function getReqCount(count) {
|
|
|
125
126
|
return count > 0 ? Math.min(count, MAX_REQ_COUNT) : 1;
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
function
|
|
129
|
+
function getResponse(res, testId) {
|
|
130
|
+
if (testId) {
|
|
131
|
+
return { testId: testId };
|
|
132
|
+
}
|
|
133
|
+
return { statusCode: res.statusCode, headers: res.headers || {} };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function handleCallback(cb, err, res, testId) {
|
|
137
|
+
if (!cb) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (testId) {
|
|
141
|
+
return cb(null, getResponse(null, testId));
|
|
142
|
+
}
|
|
143
|
+
cb(err, !err && getResponse(res));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function handleConnect(options, cb, count, testId) {
|
|
129
147
|
count = getReqCount(count);
|
|
130
148
|
options.headers['x-whistle-policy'] = 'tunnel';
|
|
131
149
|
var origOpts = options;
|
|
@@ -145,7 +163,7 @@ function handleConnect(options, cb, count) {
|
|
|
145
163
|
headers: options.headers
|
|
146
164
|
}, function(socket, svrRes, err) {
|
|
147
165
|
if (err) {
|
|
148
|
-
return execCb
|
|
166
|
+
return handleCallback(execCb, err, null, testId);
|
|
149
167
|
}
|
|
150
168
|
if (TLS_PROTOS.indexOf(options.protocol) !== -1) {
|
|
151
169
|
socket = tls.connect({
|
|
@@ -160,10 +178,7 @@ function handleConnect(options, cb, count) {
|
|
|
160
178
|
socket.write(data);
|
|
161
179
|
options.body = data = null;
|
|
162
180
|
}
|
|
163
|
-
execCb
|
|
164
|
-
statusCode: svrRes.statusCode,
|
|
165
|
-
headers: svrRes.headers
|
|
166
|
-
});
|
|
181
|
+
handleCallback(execCb, err, svrRes, testId);
|
|
167
182
|
}, config).on('error', execCb || noop);
|
|
168
183
|
}
|
|
169
184
|
}
|
|
@@ -178,7 +193,7 @@ function getReqRaw(options) {
|
|
|
178
193
|
return raw + '\r\n\r\n';
|
|
179
194
|
}
|
|
180
195
|
|
|
181
|
-
function handleWebSocket(options, cb, count) {
|
|
196
|
+
function handleWebSocket(options, cb, count, testId) {
|
|
182
197
|
count = getReqCount(count);
|
|
183
198
|
if (options.protocol === 'https:' || options.protocol === 'wss:') {
|
|
184
199
|
options.headers[common.HTTPS_FIELD] = 1;
|
|
@@ -196,7 +211,7 @@ function handleWebSocket(options, cb, count) {
|
|
|
196
211
|
}
|
|
197
212
|
common.connect(PROXY_OPTS, function(err, socket) {
|
|
198
213
|
if (err) {
|
|
199
|
-
execCb
|
|
214
|
+
handleCallback(execCb, err, null, testId);
|
|
200
215
|
} else {
|
|
201
216
|
socket.write(getReqRaw(options));
|
|
202
217
|
var data = options.body;
|
|
@@ -206,7 +221,7 @@ function handleWebSocket(options, cb, count) {
|
|
|
206
221
|
parseReq(socket, function(e) {
|
|
207
222
|
if (e) {
|
|
208
223
|
socket.destroy();
|
|
209
|
-
return execCb
|
|
224
|
+
return handleCallback(execCb, e, null, testId);
|
|
210
225
|
}
|
|
211
226
|
var statusCode = socket.statusCode;
|
|
212
227
|
if (statusCode == 101) {
|
|
@@ -226,17 +241,14 @@ function handleWebSocket(options, cb, count) {
|
|
|
226
241
|
} else {
|
|
227
242
|
socket.destroy();
|
|
228
243
|
}
|
|
229
|
-
execCb
|
|
230
|
-
statusCode: statusCode,
|
|
231
|
-
headers: socket.headers || {}
|
|
232
|
-
});
|
|
244
|
+
handleCallback(execCb, err, socket, testId);
|
|
233
245
|
}, true);
|
|
234
246
|
}
|
|
235
247
|
});
|
|
236
248
|
}
|
|
237
249
|
}
|
|
238
250
|
|
|
239
|
-
function handleHttp(options, cb, count, reqId) {
|
|
251
|
+
function handleHttp(options, cb, count, reqId, testId) {
|
|
240
252
|
count = getReqCount(count);
|
|
241
253
|
if (options.protocol === 'https:') {
|
|
242
254
|
options.headers[common.HTTPS_FIELD] = 1;
|
|
@@ -255,7 +267,8 @@ function handleHttp(options, cb, count, reqId) {
|
|
|
255
267
|
options = extend({}, origOpts);
|
|
256
268
|
}
|
|
257
269
|
var client = http.request(options, function(svrRes) {
|
|
258
|
-
if (!execCb) {
|
|
270
|
+
if (!execCb || testId) {
|
|
271
|
+
handleCallback(execCb, null, svrRes, testId);
|
|
259
272
|
return drain(svrRes);
|
|
260
273
|
}
|
|
261
274
|
svrRes.on('error', execCb);
|
|
@@ -338,7 +351,8 @@ function getCharset(headers) {
|
|
|
338
351
|
}
|
|
339
352
|
|
|
340
353
|
exports.handleRequest = function(req, res) {
|
|
341
|
-
var
|
|
354
|
+
var reqBody = req.body;
|
|
355
|
+
var fullUrl = reqBody.url;
|
|
342
356
|
if (!fullUrl || typeof fullUrl !== 'string') {
|
|
343
357
|
return res.json({ec: 2, em: 'Invalid URL'});
|
|
344
358
|
}
|
|
@@ -354,13 +368,41 @@ exports.handleRequest = function(req, res) {
|
|
|
354
368
|
}
|
|
355
369
|
var rawHeaderNames = {};
|
|
356
370
|
var clientId = req.headers[config.CLIENT_ID_HEADER];
|
|
357
|
-
var headers = parseHeaders(
|
|
358
|
-
var method = common.getMethod(
|
|
371
|
+
var headers = parseHeaders(reqBody.headers, rawHeaderNames, clientId);
|
|
372
|
+
var method = common.getMethod(reqBody.method);
|
|
359
373
|
var isWebSocket = method === 'WEBSOCKET';
|
|
374
|
+
var rules = common.trimStr(reqBody.rules);
|
|
375
|
+
if (rules) {
|
|
376
|
+
var curRules = headers['x-whistle-rule-value'];
|
|
377
|
+
if (Array.isArray(curRules)) {
|
|
378
|
+
curRules = curRules.join('\n');
|
|
379
|
+
}
|
|
380
|
+
curRules = common.trimStr(curRules);
|
|
381
|
+
if (curRules) {
|
|
382
|
+
try {
|
|
383
|
+
curRules = decodeURIComponent(curRules);
|
|
384
|
+
rules = common.removeComment(rules + '\n' + curRules);
|
|
385
|
+
} catch (e) {}
|
|
386
|
+
}
|
|
387
|
+
headers['x-whistle-rule-value'] = common.safeEncodeURIComponent(rules);
|
|
388
|
+
}
|
|
389
|
+
var type = common.trimStr(reqBody.contentType);
|
|
390
|
+
if (type) {
|
|
391
|
+
headers['content-type'] = type;
|
|
392
|
+
}
|
|
393
|
+
if (reqBody.contentLength >= 0) {
|
|
394
|
+
headers['content-length'] = reqBody.contentLength;
|
|
395
|
+
}
|
|
360
396
|
delete headers[config.WEBUI_HEAD];
|
|
361
397
|
headers[config.FROM_COM_HEADER] = '1';
|
|
362
|
-
|
|
398
|
+
var isTest = reqBody.isTest;
|
|
399
|
+
var testId;
|
|
400
|
+
if (reqBody.enableProxyRules === false || isTest) {
|
|
363
401
|
headers[config.DISABLE_RULES_HEADER] = '1';
|
|
402
|
+
if (isTest) {
|
|
403
|
+
testId = ++testIndex + '';
|
|
404
|
+
headers[config.TEST_HEADER] = testId;
|
|
405
|
+
}
|
|
364
406
|
}
|
|
365
407
|
headers.host = options.host;
|
|
366
408
|
options.clientId = clientId;
|
|
@@ -370,8 +412,8 @@ exports.handleRequest = function(req, res) {
|
|
|
370
412
|
|
|
371
413
|
var isConn = common.isConnect(options);
|
|
372
414
|
var isWs = !isConn && (isWebSocket || common.isUpgrade(options, headers));
|
|
373
|
-
var useH2 =
|
|
374
|
-
|
|
415
|
+
var useH2 = reqBody.useH2 || reqBody.isH2;
|
|
416
|
+
reqBody.useH2 = false;
|
|
375
417
|
if (isWs) {
|
|
376
418
|
headers.connection = 'Upgrade';
|
|
377
419
|
headers.upgrade = (!isWebSocket && headers.upgrade) || 'websocket';
|
|
@@ -382,7 +424,7 @@ exports.handleRequest = function(req, res) {
|
|
|
382
424
|
} else {
|
|
383
425
|
delete headers.upgrade;
|
|
384
426
|
if (!isConn && ((useH2 && (protocol === 'https:' || protocol === 'http:')) || protocol === 'h2:' || protocol === 'http2:')) {
|
|
385
|
-
|
|
427
|
+
reqBody.useH2 = true;
|
|
386
428
|
var isHttp = protocol === 'http:';
|
|
387
429
|
options.protocol = isHttp ? 'http:' : 'https:';
|
|
388
430
|
if (!headers[config.ALPN_PROTOCOL_HEADER]) {
|
|
@@ -390,8 +432,8 @@ exports.handleRequest = function(req, res) {
|
|
|
390
432
|
}
|
|
391
433
|
}
|
|
392
434
|
}
|
|
393
|
-
if (!
|
|
394
|
-
handleComposerHistory(
|
|
435
|
+
if (!reqBody.noStore && !testId && reqBody.needResponse && common.checkHistory(reqBody)) {
|
|
436
|
+
handleComposerHistory(reqBody, isConn);
|
|
395
437
|
dataCenter.saveData({
|
|
396
438
|
type: 'composer',
|
|
397
439
|
history: composerHistory
|
|
@@ -399,15 +441,15 @@ exports.handleRequest = function(req, res) {
|
|
|
399
441
|
}
|
|
400
442
|
|
|
401
443
|
var getBody = function(cb) {
|
|
402
|
-
var base64 =
|
|
403
|
-
var body = base64 ||
|
|
444
|
+
var base64 = reqBody.base64;
|
|
445
|
+
var body = base64 || reqBody.body;
|
|
404
446
|
if (!isWs) {
|
|
405
447
|
delete headers.trailer;
|
|
406
448
|
}
|
|
407
449
|
if (isWs || isConn || common.hasRequestBody(options)) {
|
|
408
450
|
body = body && common.toBuffer(body, base64 ? 'base64' : getCharset(headers));
|
|
409
451
|
options.body = body;
|
|
410
|
-
if (!isWs && !isConn && body &&
|
|
452
|
+
if (!isWs && !isConn && body && reqBody.isGzip) {
|
|
411
453
|
gzip(body, function(err, gzipData) {
|
|
412
454
|
if (err) {
|
|
413
455
|
return cb(err);
|
|
@@ -439,7 +481,7 @@ exports.handleRequest = function(req, res) {
|
|
|
439
481
|
getBody(function(err) {
|
|
440
482
|
options.headers = formatHeaders(headers, rawHeaderNames);
|
|
441
483
|
var done;
|
|
442
|
-
var needResponse = req.query.needResponse ||
|
|
484
|
+
var needResponse = req.query.needResponse || reqBody.needResponse;
|
|
443
485
|
var handleResponse = needResponse ? function(err, data) {
|
|
444
486
|
if (done) {
|
|
445
487
|
return;
|
|
@@ -453,23 +495,23 @@ exports.handleRequest = function(req, res) {
|
|
|
453
495
|
}});
|
|
454
496
|
return;
|
|
455
497
|
}
|
|
456
|
-
common.sendGzip(req, res, {ec: 0,
|
|
498
|
+
common.sendGzip(req, res, {ec: 0, res: data || ''});
|
|
457
499
|
} : null;
|
|
458
500
|
if (err) {
|
|
459
501
|
return handleResponse && handleResponse(err);
|
|
460
502
|
}
|
|
461
|
-
var count =
|
|
462
|
-
count = count > 0 ? count :
|
|
503
|
+
var count = reqBody.repeatCount;
|
|
504
|
+
count = count > 0 ? count : reqBody.repeatTimes;
|
|
463
505
|
if (isWs) {
|
|
464
506
|
options.method = 'GET';
|
|
465
|
-
handleWebSocket(options, handleResponse, count);
|
|
507
|
+
handleWebSocket(options, handleResponse, count, testId);
|
|
466
508
|
} else if (isConn) {
|
|
467
|
-
handleConnect(options, handleResponse, count);
|
|
509
|
+
handleConnect(options, handleResponse, count, testId);
|
|
468
510
|
} else {
|
|
469
|
-
handleHttp(options, handleResponse, count,
|
|
511
|
+
handleHttp(options, handleResponse, count, reqBody.reqId, testId);
|
|
470
512
|
}
|
|
471
513
|
if (!handleResponse) {
|
|
472
|
-
res.json({ec: 0
|
|
514
|
+
res.json({ec: 0});
|
|
473
515
|
}
|
|
474
516
|
});
|
|
475
517
|
};
|
package/lib/tunnel.js
CHANGED
|
@@ -91,6 +91,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
91
91
|
reqSocket.headers = headers;
|
|
92
92
|
reqSocket.fromTunnel = req.fromTunnel;
|
|
93
93
|
reqSocket.fromComposer = req.fromComposer;
|
|
94
|
+
reqSocket._testId = req._testId;
|
|
94
95
|
req.isPluginReq = reqSocket.isPluginReq = util.checkPluginReqOnce(req, true);
|
|
95
96
|
util.onSocketEnd(reqSocket, function (err) {
|
|
96
97
|
// 处理可能的证书校验出错
|
|
@@ -100,6 +101,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
100
101
|
id: req.reqId,
|
|
101
102
|
url: options.host,
|
|
102
103
|
fc: req.fromComposer ? 1 : undefined,
|
|
104
|
+
testId: req._testId,
|
|
103
105
|
startTime: now,
|
|
104
106
|
dnsTime: now,
|
|
105
107
|
captureError: true,
|
|
@@ -319,6 +321,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
319
321
|
id: req.reqId,
|
|
320
322
|
url: options.host,
|
|
321
323
|
fc: req.fromComposer ? 1 : undefined,
|
|
324
|
+
testId: req._testId,
|
|
322
325
|
startTime: Date.now(),
|
|
323
326
|
rules: _rules,
|
|
324
327
|
req: reqData,
|
package/lib/upgrade.js
CHANGED
|
@@ -167,6 +167,7 @@ function upgradeHandler(req, socket) {
|
|
|
167
167
|
socket.url = req.url;
|
|
168
168
|
socket.fromTunnel = req.fromTunnel;
|
|
169
169
|
socket.fromComposer = req.fromComposer;
|
|
170
|
+
socket._testId = req._testId;
|
|
170
171
|
socket.enableXFF = req.enableXFF;
|
|
171
172
|
socket._isInternalReq = req._isInternalReq;
|
|
172
173
|
socket.isInternalUrl = req.isInternalUrl;
|
package/lib/util/common.js
CHANGED
|
@@ -1127,6 +1127,10 @@ function isNum(n) {
|
|
|
1127
1127
|
return typeof n === 'number';
|
|
1128
1128
|
}
|
|
1129
1129
|
|
|
1130
|
+
exports.trimStr = function(str) {
|
|
1131
|
+
return typeof str === 'string' ? str.trim() : '';
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1130
1134
|
exports.parsePlainText = function (text, resolveKeys) {
|
|
1131
1135
|
var result;
|
|
1132
1136
|
text.split(LINE_END_RE).forEach(function(line) {
|
|
@@ -2034,4 +2038,10 @@ exports.writeTempFile = function (value, callback) {
|
|
|
2034
2038
|
writeFile(path.join(TEMP_FILES_PATH, filename), value, function(err) {
|
|
2035
2039
|
callback(err, filename);
|
|
2036
2040
|
});
|
|
2037
|
-
};
|
|
2041
|
+
};
|
|
2042
|
+
|
|
2043
|
+
var COMMENT_RE = /#[^\r\n]*/g;
|
|
2044
|
+
|
|
2045
|
+
exports.removeComment = function(text) {
|
|
2046
|
+
return text.replace(COMMENT_RE, '').trim();
|
|
2047
|
+
};
|
package/lib/util/data-server.js
CHANGED
|
@@ -577,6 +577,16 @@ module.exports = function init(_proxy) {
|
|
|
577
577
|
}
|
|
578
578
|
return item;
|
|
579
579
|
};
|
|
580
|
+
proxy.getTestItem = function(id) {
|
|
581
|
+
var list = Object.values(reqData);
|
|
582
|
+
for (var i = 0, len = list.length; i < len; i++) {
|
|
583
|
+
var item = list[i];
|
|
584
|
+
if (item.testId === id) {
|
|
585
|
+
return item;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
|
|
580
590
|
proxy.abortRequest = function (id) {
|
|
581
591
|
var item = id && reqData[id];
|
|
582
592
|
item && item.abort && item.abort();
|
package/lib/util/index.js
CHANGED
|
@@ -29,6 +29,7 @@ var h2Consts = config.enableH2 ? require('http2').constants : {};
|
|
|
29
29
|
var protocols = protoMgr.protocols;
|
|
30
30
|
var resProtocols = protoMgr.resProtocols;
|
|
31
31
|
var uid = config.uid;
|
|
32
|
+
var trimStr = common.trimStr;
|
|
32
33
|
var parseQuery = common.parseQuery;
|
|
33
34
|
var supportsBr = common.supportsBr;
|
|
34
35
|
var isLocalIp = common.isLocalIp;
|
|
@@ -126,6 +127,7 @@ workerIndex = workerIndex >= 0 ? common.padLeft(config.workerIndex, 3) : '';
|
|
|
126
127
|
|
|
127
128
|
|
|
128
129
|
exports.sendRes = common.sendRes;
|
|
130
|
+
exports.trimStr = trimStr;
|
|
129
131
|
exports.THEME_STYLE = THEME_STYLE;
|
|
130
132
|
exports.encodeNonLatin1Char = encodeNonLatin1Char;
|
|
131
133
|
exports.isJson = common.isJson;
|
|
@@ -2359,15 +2361,6 @@ exports.transformReq = function(req, res, port, host, html) {
|
|
|
2359
2361
|
return client;
|
|
2360
2362
|
};
|
|
2361
2363
|
|
|
2362
|
-
function trimStr(str) {
|
|
2363
|
-
if (typeof str !== 'string') {
|
|
2364
|
-
return '';
|
|
2365
|
-
}
|
|
2366
|
-
return str.trim();
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
|
-
exports.trimStr = trimStr;
|
|
2370
|
-
|
|
2371
2364
|
function hasHeaderRules(headers) {
|
|
2372
2365
|
return (
|
|
2373
2366
|
headers['x-whistle-rule-key'] ||
|
|
@@ -3389,19 +3382,25 @@ exports.parseRange = function (req, size) {
|
|
|
3389
3382
|
};
|
|
3390
3383
|
|
|
3391
3384
|
exports.parseClientInfo = function (req) {
|
|
3392
|
-
|
|
3385
|
+
var headers = req.headers;
|
|
3386
|
+
var testId = headers[config.TEST_HEADER];
|
|
3387
|
+
if (testId) {
|
|
3388
|
+
delete headers[config.TEST_HEADER];
|
|
3389
|
+
req._testId = testId;
|
|
3390
|
+
}
|
|
3391
|
+
if (headers[config.FROM_COM_HEADER] === '1') {
|
|
3393
3392
|
req.fromComposer = true;
|
|
3394
|
-
req._disabledProxyRules = !!
|
|
3395
|
-
delete
|
|
3396
|
-
delete
|
|
3393
|
+
req._disabledProxyRules = !!headers[config.DISABLE_RULES_HEADER];
|
|
3394
|
+
delete headers[config.FROM_COM_HEADER];
|
|
3395
|
+
delete headers[config.DISABLE_RULES_HEADER];
|
|
3397
3396
|
}
|
|
3398
3397
|
var socket = req.socket || '';
|
|
3399
3398
|
if (socket.fromTunnel) {
|
|
3400
3399
|
req.fromTunnel = true;
|
|
3401
3400
|
}
|
|
3402
|
-
var clientInfo =
|
|
3401
|
+
var clientInfo = headers[clientInfoKey];
|
|
3403
3402
|
if (clientInfo) {
|
|
3404
|
-
delete
|
|
3403
|
+
delete headers[clientInfoKey];
|
|
3405
3404
|
clientInfo = String(clientInfo).split(',');
|
|
3406
3405
|
if (!net.isIP(clientInfo[0]) || !(clientInfo[1] > 0)) {
|
|
3407
3406
|
return '';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whistle",
|
|
3
3
|
"description": "HTTP, HTTP2, HTTPS, Websocket debugging proxy",
|
|
4
|
-
"version": "2.10.
|
|
4
|
+
"version": "2.10.5",
|
|
5
5
|
"dataDirname": ".whistle",
|
|
6
6
|
"localUIHost": "local.whistlejs.com",
|
|
7
7
|
"port": 8899,
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"parseurl": "^1.3.1",
|
|
54
54
|
"pfork": "^0.6.3",
|
|
55
55
|
"pipestream": "^0.7.5",
|
|
56
|
-
"set-global-proxy": "^0.4.
|
|
56
|
+
"set-global-proxy": "^0.4.2",
|
|
57
57
|
"sni": "1.0.0",
|
|
58
58
|
"sockx": "^0.2.3",
|
|
59
59
|
"starting": "^8.0.3",
|