whistle 2.10.5 → 2.10.7
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 +2 -2
- package/assets/modal.html +2 -2
- package/assets/tab.html +2 -2
- package/bin/api.js +545 -0
- package/bin/import.js +3 -3
- package/bin/plugin.js +4 -8
- package/bin/use.js +22 -8
- package/bin/util.js +12 -7
- package/bin/whistle.js +11 -1
- package/biz/webui/cgi-bin/abort.js +14 -5
- package/biz/webui/cgi-bin/frames.js +12 -0
- package/biz/webui/cgi-bin/get-session.js +7 -3
- package/biz/webui/cgi-bin/is-enabled-https.js +6 -0
- package/biz/webui/cgi-bin/plugins/disable-plugin.js +16 -7
- package/biz/webui/cgi-bin/plugins/list.js +17 -0
- package/biz/webui/cgi-bin/plugins/plugin.js +21 -0
- package/biz/webui/cgi-bin/plugins/status.js +21 -0
- package/biz/webui/cgi-bin/rules/is-multi-select.js +7 -0
- package/biz/webui/cgi-bin/rules/move-top.js +11 -0
- package/biz/webui/cgi-bin/rules/select.js +1 -1
- package/biz/webui/cgi-bin/rules/select2.js +16 -0
- package/biz/webui/cgi-bin/rules/status.js +6 -0
- package/biz/webui/cgi-bin/rules/unselect.js +3 -2
- package/biz/webui/cgi-bin/rules/unselect2.js +18 -0
- package/biz/webui/cgi-bin/rules/value.js +19 -0
- package/biz/webui/cgi-bin/sessions.js +6 -0
- package/biz/webui/cgi-bin/util.js +45 -20
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +51 -51
- package/biz/webui/lib/index.js +1 -3
- package/lib/https/index.js +7 -5
- package/lib/init.js +1 -0
- package/lib/inspectors/data.js +39 -34
- package/lib/inspectors/req.js +9 -6
- package/lib/inspectors/res.js +10 -14
- package/lib/plugins/index.js +2 -2
- package/lib/plugins/load-plugin.js +19 -8
- package/lib/rules/util.js +20 -10
- package/lib/service/composer.js +7 -22
- package/lib/service/data-center.js +0 -12
- package/lib/service/generate-saz.js +2 -2
- package/lib/service/service.js +8 -7
- package/lib/service/util.js +6 -16
- package/lib/socket-mgr.js +23 -17
- package/lib/tunnel.js +7 -17
- package/lib/upgrade.js +4 -8
- package/lib/util/common.js +78 -11
- package/lib/util/data-server.js +273 -0
- package/lib/util/file-mgr.js +7 -4
- package/lib/util/http-mgr.js +17 -9
- package/lib/util/index.js +67 -54
- package/lib/util/parse-url.js +11 -9
- package/lib/util/patch.js +2 -6
- package/lib/util/speed-transform.js +17 -6
- package/lib/util/whistle-transform.js +18 -7
- package/package.json +10 -7
package/biz/webui/lib/index.js
CHANGED
|
@@ -36,7 +36,6 @@ var uploadJsonParser = bodyParser.json(UPLOAD_PARSE_CONF);
|
|
|
36
36
|
var GET_METHOD_RE = /^get$/i;
|
|
37
37
|
var WEINRE_RE = /^\/weinre\/.*/;
|
|
38
38
|
var ALLOW_PLUGIN_PATHS = ['/cgi-bin/rules/list2', '/cgi-bin/values/list2', '/cgi-bin/get-custom-certs-info'];
|
|
39
|
-
var SPECIAL_PATHS = ['/cgi-bin/rules/project'];
|
|
40
39
|
var DONT_CHECK_PATHS = ['/cgi-bin/server-info', '/cgi-bin/plugins/is-enable', '/cgi-bin/plugins/get-plugins',
|
|
41
40
|
'/preview.html', '/cgi-bin/rootca', '/cgi-bin/check-update', '/cgi-bin/log/set', '/cgi-bin/status'];
|
|
42
41
|
var GUEST_PATHS = ['/cgi-bin/composer', '/cgi-bin/socket/data', '/cgi-bin/abort', '/cgi-bin/socket/abort',
|
|
@@ -196,8 +195,7 @@ function checkAuth(req, res) {
|
|
|
196
195
|
if (verifyLogin(req, res, auth)) {
|
|
197
196
|
return true;
|
|
198
197
|
}
|
|
199
|
-
if (config.specialAuth &&
|
|
200
|
-
config.specialAuth === req.headers['x-whistle-special-auth']) {
|
|
198
|
+
if (config.specialAuth && config.specialAuth === req.headers['x-whistle-special-auth']) {
|
|
201
199
|
return true;
|
|
202
200
|
}
|
|
203
201
|
requireLogin(req, res);
|
package/lib/https/index.js
CHANGED
|
@@ -198,7 +198,7 @@ function resolveWebsocket(socket, wss) {
|
|
|
198
198
|
var delay = reqDelay + resDelay;
|
|
199
199
|
if (delay > 0) {
|
|
200
200
|
clearTimeout(timeout);
|
|
201
|
-
setTimeout(end, delay);
|
|
201
|
+
timeout = setTimeout(end, delay);
|
|
202
202
|
} else {
|
|
203
203
|
end();
|
|
204
204
|
}
|
|
@@ -304,7 +304,7 @@ function resolveWebsocket(socket, wss) {
|
|
|
304
304
|
var reqDelay = util.getMatcherValue(_rules.reqDelay);
|
|
305
305
|
if (reqDelay > 0) {
|
|
306
306
|
clearTimeout(timeout);
|
|
307
|
-
setTimeout(function () {
|
|
307
|
+
timeout = setTimeout(function () {
|
|
308
308
|
timeout = setTimeout(function () {
|
|
309
309
|
destroy(util.TIMEOUT_ERR);
|
|
310
310
|
}, CONN_TIMEOUT);
|
|
@@ -779,7 +779,7 @@ function resolveWebsocket(socket, wss) {
|
|
|
779
779
|
var curResHeaders = (reqSocket.headers = res.headers);
|
|
780
780
|
socket.resHeaders = curResHeaders;
|
|
781
781
|
getResRules(socket, res, function () {
|
|
782
|
-
util.delay(util.getMatcherValue(_rules.resDelay), function () {
|
|
782
|
+
util.setDelayTimer(socket, util.delay(util.getMatcherValue(_rules.resDelay), function () {
|
|
783
783
|
if (util.needAbortRes(socket)) {
|
|
784
784
|
socket.__statusCode = res.statusCode;
|
|
785
785
|
return destroy();
|
|
@@ -812,7 +812,7 @@ function resolveWebsocket(socket, wss) {
|
|
|
812
812
|
resData.statusCode = code;
|
|
813
813
|
reqEmitter.emit('response', data);
|
|
814
814
|
execCallback(null, reqSocket);
|
|
815
|
-
});
|
|
815
|
+
}));
|
|
816
816
|
});
|
|
817
817
|
},
|
|
818
818
|
true
|
|
@@ -1015,8 +1015,10 @@ function toHttp1(req, res) {
|
|
|
1015
1015
|
var handleAbort = function () {
|
|
1016
1016
|
if (client) {
|
|
1017
1017
|
client.abort();
|
|
1018
|
-
res.destroy();
|
|
1019
1018
|
client = null;
|
|
1019
|
+
if (!res.writableEnded && !res.finished) {
|
|
1020
|
+
res.destroy();
|
|
1021
|
+
}
|
|
1020
1022
|
}
|
|
1021
1023
|
};
|
|
1022
1024
|
addReqInfo(req);
|
package/lib/init.js
CHANGED
package/lib/inspectors/data.js
CHANGED
|
@@ -19,7 +19,7 @@ function getZipType(options) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function unzipBody(options, body, callback) {
|
|
22
|
-
return zlib.unzip(getZipType(options), body, callback);
|
|
22
|
+
return zlib.unzip(getZipType(options), util.formatBuffer(body), callback);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function checkType(res) {
|
|
@@ -244,7 +244,8 @@ function emitDataEvents(req, res, proxy) {
|
|
|
244
244
|
var captureReqStream;
|
|
245
245
|
var maxReqSize;
|
|
246
246
|
var reqInfo;
|
|
247
|
-
var setReqBody = function (
|
|
247
|
+
var setReqBody = function (end) {
|
|
248
|
+
reqBody = util.formatBuffer(reqBody);
|
|
248
249
|
if (captureReqStream && cseSep) {
|
|
249
250
|
reqBody = parseFrame(reqBody, false, end);
|
|
250
251
|
} else {
|
|
@@ -257,7 +258,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
257
258
|
maxReqSize = useBigData ? BIG_DATA_SIZE : (captureReqStream ? MAX_REQ_BODY_SIZE : MAX_SIZE);
|
|
258
259
|
if (captureReqStream) {
|
|
259
260
|
data.isCse = !!cseSep;
|
|
260
|
-
reqBody && !reqData.body && setReqBody(
|
|
261
|
+
reqBody && !reqData.body && setReqBody();
|
|
261
262
|
}
|
|
262
263
|
}
|
|
263
264
|
};
|
|
@@ -277,32 +278,33 @@ function emitDataEvents(req, res, proxy) {
|
|
|
277
278
|
var end = stream.end;
|
|
278
279
|
stream.write = function (chunk) {
|
|
279
280
|
if (chunk) {
|
|
281
|
+
reqData.size += chunk.length;
|
|
280
282
|
if (reqBody || reqBody === null) {
|
|
281
283
|
if (useFrames) {
|
|
282
284
|
reqBody = '';
|
|
283
285
|
} else {
|
|
284
|
-
reqBody =
|
|
286
|
+
reqBody = util.joinBuffer(reqBody, chunk);
|
|
285
287
|
if (captureReqStream) {
|
|
286
|
-
setReqBody(
|
|
287
|
-
|
|
288
|
-
|
|
288
|
+
setReqBody();
|
|
289
|
+
if (reqBody && reqBody.length > maxReqSize) {
|
|
290
|
+
reqBody = false;
|
|
291
|
+
}
|
|
292
|
+
} else if (reqData.size > maxReqSize) {
|
|
289
293
|
reqBody = false;
|
|
290
294
|
}
|
|
291
295
|
}
|
|
292
296
|
}
|
|
293
|
-
reqData.size += chunk.length;
|
|
294
297
|
}
|
|
295
298
|
updateEvent && proxy.emit(updateEvent, req.fullUrl, false);
|
|
296
299
|
return write.apply(this, arguments);
|
|
297
300
|
};
|
|
298
301
|
stream.end = function (chunk) {
|
|
299
|
-
if (chunk) {
|
|
300
|
-
reqData.size += chunk.length;
|
|
301
|
-
reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
|
|
302
|
-
}
|
|
303
302
|
requestTime = Date.now();
|
|
304
303
|
if (useFrames) {
|
|
305
304
|
reqBody = '';
|
|
305
|
+
} else if (chunk) {
|
|
306
|
+
reqData.size += chunk.length;
|
|
307
|
+
reqBody = util.joinBuffer(reqBody, chunk);
|
|
306
308
|
}
|
|
307
309
|
unzipBody(reqInfo, reqBody, function (err, body) {
|
|
308
310
|
setRequestTime(requestTime);
|
|
@@ -310,7 +312,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
310
312
|
data.endTime = endTime;
|
|
311
313
|
}
|
|
312
314
|
reqBody = err ? util.getErrorStack(err) : body;
|
|
313
|
-
setReqBody(
|
|
315
|
+
setReqBody(true);
|
|
314
316
|
!data.isCse && setUnzipSize(body, reqData);
|
|
315
317
|
checkBodySize(reqData, useBigData);
|
|
316
318
|
});
|
|
@@ -339,6 +341,14 @@ function emitDataEvents(req, res, proxy) {
|
|
|
339
341
|
}
|
|
340
342
|
}
|
|
341
343
|
var maxResSize = useBigData ? BIG_DATA_SIZE : (captureStream ? MAX_RES_BODY_SIZE : MAX_SIZE);
|
|
344
|
+
var setResBody = function (end) {
|
|
345
|
+
resBody = util.formatBuffer(resBody);
|
|
346
|
+
if (isSse) {
|
|
347
|
+
resBody = parseFrame(resBody, true, end);
|
|
348
|
+
} else {
|
|
349
|
+
resData.body = resBody;
|
|
350
|
+
}
|
|
351
|
+
};
|
|
342
352
|
data.isSse = isSse;
|
|
343
353
|
captureStream && updateReqInfo();
|
|
344
354
|
if (!cleared && util.hasBody(info, req) && checkType(info)) {
|
|
@@ -353,46 +363,39 @@ function emitDataEvents(req, res, proxy) {
|
|
|
353
363
|
var end = stream.end;
|
|
354
364
|
stream.write = function (chunk) {
|
|
355
365
|
if (chunk) {
|
|
366
|
+
resData.size += chunk.length;
|
|
356
367
|
if (resBody || resBody === null) {
|
|
357
368
|
if (useFrames) {
|
|
358
369
|
resBody = '';
|
|
359
370
|
} else {
|
|
360
|
-
resBody =
|
|
371
|
+
resBody = util.joinBuffer(resBody, chunk);
|
|
361
372
|
if (captureStream) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
resData.body = resBody;
|
|
373
|
+
setResBody();
|
|
374
|
+
if (resBody && resBody.length > maxResSize) {
|
|
375
|
+
resBody = false;
|
|
366
376
|
}
|
|
367
|
-
}
|
|
368
|
-
if (resBody && resBody.length > maxResSize) {
|
|
377
|
+
} else if (resData.size > maxResSize) {
|
|
369
378
|
resBody = false;
|
|
370
379
|
}
|
|
371
380
|
}
|
|
372
381
|
}
|
|
373
|
-
resData.size += chunk.length;
|
|
374
382
|
}
|
|
375
383
|
updateEvent && proxy.emit(updateEvent, req.fullUrl, true);
|
|
376
384
|
return write.apply(this, arguments);
|
|
377
385
|
};
|
|
378
386
|
stream.end = function (chunk) {
|
|
379
|
-
if (chunk) {
|
|
380
|
-
resData.size += chunk.length;
|
|
381
|
-
resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
|
|
382
|
-
}
|
|
383
387
|
endTime = Date.now();
|
|
384
388
|
delete data.abort;
|
|
385
389
|
if (useFrames) {
|
|
386
390
|
resBody = '';
|
|
391
|
+
} else if (chunk) {
|
|
392
|
+
resData.size += chunk.length;
|
|
393
|
+
resBody = util.joinBuffer(resBody, chunk);
|
|
387
394
|
}
|
|
388
395
|
resData.hasGzipError = unzipBody(info, resBody, function (err, body) {
|
|
389
396
|
if (!data.resError) {
|
|
390
397
|
resBody = err ? util.getErrorStack(err) : body;
|
|
391
|
-
|
|
392
|
-
resBody = parseFrame(resBody, true, true);
|
|
393
|
-
} else {
|
|
394
|
-
resData.body = resBody;
|
|
395
|
-
}
|
|
398
|
+
setResBody(true);
|
|
396
399
|
}
|
|
397
400
|
!isSse && setUnzipSize(body, resData);
|
|
398
401
|
checkBodySize(resData, useBigData);
|
|
@@ -442,13 +445,14 @@ function emitDataEvents(req, res, proxy) {
|
|
|
442
445
|
|
|
443
446
|
function handleError(err) {
|
|
444
447
|
req._hasError = true;
|
|
448
|
+
util.clearDelayTimer(req);
|
|
445
449
|
if (!data || endTime || data.endTime || (data.responseTime && !err)) {
|
|
446
450
|
return;
|
|
447
451
|
}
|
|
448
452
|
!endTime && setEndTime();
|
|
449
453
|
delete data.abort;
|
|
450
|
-
var msg = err && err.message;
|
|
451
|
-
if (
|
|
454
|
+
// 不能乱优化,跟 var msg = err && err.message; if (msg !== 'Aborted' && msg !== 'aborted') 不一样
|
|
455
|
+
if (err && err.message !== 'Aborted' && err.message !== 'aborted') {
|
|
452
456
|
data.resError = true;
|
|
453
457
|
if (resData.body) {
|
|
454
458
|
data.errMsg = util.getErrorStack(err);
|
|
@@ -531,10 +535,11 @@ function emitDataEvents(req, res, proxy) {
|
|
|
531
535
|
|
|
532
536
|
module.exports = function (req, res, next) {
|
|
533
537
|
emitDataEvents(req, res, this);
|
|
534
|
-
util.
|
|
538
|
+
var reqDelay = util.getMatcherValue(req.rules.reqDelay);
|
|
539
|
+
util.setDelayTimer(req, util.delay(reqDelay, function () {
|
|
535
540
|
if (util.needAbortReq(req)) {
|
|
536
541
|
return res.destroy();
|
|
537
542
|
}
|
|
538
543
|
next();
|
|
539
|
-
});
|
|
544
|
+
}));
|
|
540
545
|
};
|
package/lib/inspectors/req.js
CHANGED
|
@@ -10,7 +10,6 @@ var handleWeinre = require('./weinre');
|
|
|
10
10
|
var handleLog = require('./log');
|
|
11
11
|
|
|
12
12
|
var Transform = require('pipestream').Transform;
|
|
13
|
-
var WhistleTransform = util.WhistleTransform;
|
|
14
13
|
var ReplacePatternTransform = util.ReplacePatternTransform;
|
|
15
14
|
var ReplaceStringTransform = util.ReplaceStringTransform;
|
|
16
15
|
var FileWriterTransform = util.FileWriterTransform;
|
|
@@ -127,7 +126,7 @@ function handleReq(req, data, reqRules, delType) {
|
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
util.isWhistleTransformData(data) &&
|
|
130
|
-
req.addZipTransform(new WhistleTransform(data));
|
|
129
|
+
req.addZipTransform(new util.WhistleTransform(data, req));
|
|
131
130
|
var opList = util.parseHeaderReplace(req.rules.headerReplace).req;
|
|
132
131
|
if (opList) {
|
|
133
132
|
var host = req.headers.host;
|
|
@@ -159,6 +158,7 @@ function handleParams(req, params, urlParams, enableBigData) {
|
|
|
159
158
|
var delProps = util.parseDelReqBody(req);
|
|
160
159
|
var hasBody;
|
|
161
160
|
var buffer;
|
|
161
|
+
var len = 0;
|
|
162
162
|
if (params || delProps) {
|
|
163
163
|
var maxReqSize = enableBigData || util.isEnable(req, 'reqMergeBigData') ? BIG_MAX_REQ_SIZE : MAX_REQ_SIZE;
|
|
164
164
|
var transform;
|
|
@@ -171,15 +171,18 @@ function handleParams(req, params, urlParams, enableBigData) {
|
|
|
171
171
|
transform._transform = function (chunk, _, callback) {
|
|
172
172
|
if (chunk) {
|
|
173
173
|
if (!interrupt) {
|
|
174
|
-
|
|
174
|
+
len += chunk.length;
|
|
175
|
+
buffer = buffer || [];
|
|
176
|
+
buffer.push(chunk);
|
|
175
177
|
chunk = null;
|
|
176
|
-
if (
|
|
178
|
+
if (len > maxReqSize) {
|
|
177
179
|
interrupt = true;
|
|
178
|
-
chunk = buffer;
|
|
180
|
+
chunk = Buffer.concat(buffer, len);
|
|
179
181
|
buffer = null;
|
|
180
182
|
}
|
|
181
183
|
}
|
|
182
184
|
} else if (buffer && buffer.length) {
|
|
185
|
+
buffer = util.formatBuffer(buffer, len);
|
|
183
186
|
var body;
|
|
184
187
|
var isGBK = !util.isUtf8(buffer);
|
|
185
188
|
if (isGBK) {
|
|
@@ -388,7 +391,7 @@ function handleParams(req, params, urlParams, enableBigData) {
|
|
|
388
391
|
lastChunk = !chunk;
|
|
389
392
|
if (chunk && preBuffer !== null) {
|
|
390
393
|
preBuffer = preBuffer ? Buffer.concat([preBuffer, chunk]) : chunk;
|
|
391
|
-
if (
|
|
394
|
+
if (preBuffer.length <= length) {
|
|
392
395
|
return callback(null, lastChunk ? preBuffer : null);
|
|
393
396
|
}
|
|
394
397
|
if (!util.startWithList(preBuffer, startBoundary)) {
|
package/lib/inspectors/res.js
CHANGED
|
@@ -11,10 +11,6 @@ var pluginMgr = require('../plugins');
|
|
|
11
11
|
var hparser = require('hparser');
|
|
12
12
|
var config = require('../config');
|
|
13
13
|
|
|
14
|
-
var WhistleTransform = util.WhistleTransform;
|
|
15
|
-
var SpeedTransform = util.SpeedTransform;
|
|
16
|
-
var ReplacePatternTransform = util.ReplacePatternTransform;
|
|
17
|
-
var ReplaceStringTransform = util.ReplaceStringTransform;
|
|
18
14
|
var FileWriterTransform = util.FileWriterTransform;
|
|
19
15
|
var formatHeaders = hparser.formatHeaders;
|
|
20
16
|
var getRawHeaderNames = hparser.getRawHeaderNames;
|
|
@@ -89,10 +85,10 @@ function showDnsError(res, err) {
|
|
|
89
85
|
function setCookies(headers, data) {
|
|
90
86
|
var newCookies = data.headers['set-cookie'];
|
|
91
87
|
if (!Array.isArray(newCookies)) {
|
|
92
|
-
if (!newCookies
|
|
88
|
+
if (!util.isString(newCookies)) {
|
|
93
89
|
return;
|
|
94
90
|
}
|
|
95
|
-
newCookies = newCookies
|
|
91
|
+
newCookies = [newCookies];
|
|
96
92
|
}
|
|
97
93
|
if (newCookies.length) {
|
|
98
94
|
var cookies = headers['set-cookie'];
|
|
@@ -105,12 +101,12 @@ function setCookies(headers, data) {
|
|
|
105
101
|
var newNameMap = {};
|
|
106
102
|
newCookies.forEach(function (cookie) {
|
|
107
103
|
var index = cookie.indexOf('=');
|
|
108
|
-
var name = index == -1 ?
|
|
104
|
+
var name = index == -1 ? cookie : cookie.substring(0, index);
|
|
109
105
|
newNameMap[name] = 1;
|
|
110
106
|
});
|
|
111
107
|
cookies.forEach(function (cookie) {
|
|
112
108
|
var index = cookie.indexOf('=');
|
|
113
|
-
var name = index == -1 ?
|
|
109
|
+
var name = index == -1 ? cookie : cookie.substring(0, index);
|
|
114
110
|
if (!newNameMap[name]) {
|
|
115
111
|
newCookies.push(cookie);
|
|
116
112
|
}
|
|
@@ -137,9 +133,9 @@ function handleReplace(res, replacement) {
|
|
|
137
133
|
util.isOriginalRegExp(pattern) &&
|
|
138
134
|
(pattern = util.toOriginalRegExp(pattern))
|
|
139
135
|
) {
|
|
140
|
-
res.addTextTransform(new ReplacePatternTransform(pattern, value, util.isSSE(res)));
|
|
136
|
+
res.addTextTransform(new util.ReplacePatternTransform(pattern, value, util.isSSE(res)));
|
|
141
137
|
} else if (pattern) {
|
|
142
|
-
res.addTextTransform(new ReplaceStringTransform(pattern, value, util.isSSE(res)));
|
|
138
|
+
res.addTextTransform(new util.ReplaceStringTransform(pattern, value, util.isSSE(res)));
|
|
143
139
|
}
|
|
144
140
|
});
|
|
145
141
|
}
|
|
@@ -1008,7 +1004,7 @@ module.exports = function (req, res, next) {
|
|
|
1008
1004
|
data.top = resPrepend;
|
|
1009
1005
|
data.bottom = resAppend;
|
|
1010
1006
|
|
|
1011
|
-
var speedTransform = data.speed || data.delay ? new SpeedTransform(data) : null;
|
|
1007
|
+
var speedTransform = data.speed || data.delay ? new util.SpeedTransform(data, req) : null;
|
|
1012
1008
|
delete data.headers;
|
|
1013
1009
|
delete data.speed;
|
|
1014
1010
|
delete data.delay;
|
|
@@ -1113,7 +1109,7 @@ module.exports = function (req, res, next) {
|
|
|
1113
1109
|
}
|
|
1114
1110
|
if (util.isWhistleTransformData(data)) {
|
|
1115
1111
|
data.noDoctype = util.isDisable(req, 'doctype');
|
|
1116
|
-
res.addZipTransform(new WhistleTransform(data));
|
|
1112
|
+
res.addZipTransform(new util.WhistleTransform(data, req));
|
|
1117
1113
|
}
|
|
1118
1114
|
if (hasResBody) {
|
|
1119
1115
|
handleReplace(res, replacement);
|
|
@@ -1166,7 +1162,7 @@ module.exports = function (req, res, next) {
|
|
|
1166
1162
|
if (_resHeaders[config.ALPN_PROTOCOL_HEADER] === 'h2') {
|
|
1167
1163
|
req.useH2 = true;
|
|
1168
1164
|
}
|
|
1169
|
-
util.delay(
|
|
1165
|
+
util.setDelayTimer(req, util.delay(
|
|
1170
1166
|
util.getMatcherValue(resRules.resDelay),
|
|
1171
1167
|
function () {
|
|
1172
1168
|
if (req._hasError) {
|
|
@@ -1299,7 +1295,7 @@ module.exports = function (req, res, next) {
|
|
|
1299
1295
|
util.emitError(res, e);
|
|
1300
1296
|
}
|
|
1301
1297
|
}
|
|
1302
|
-
);
|
|
1298
|
+
));
|
|
1303
1299
|
},
|
|
1304
1300
|
util.isEnable(req, 'forceReqWrite')
|
|
1305
1301
|
);
|
package/lib/plugins/index.js
CHANGED
|
@@ -516,8 +516,8 @@ var delayTimer;
|
|
|
516
516
|
|
|
517
517
|
function refreshPlugins() {
|
|
518
518
|
updating = true;
|
|
519
|
-
|
|
520
|
-
|
|
519
|
+
clearTimeout(delayTimer);
|
|
520
|
+
clearTimeout(updateTimer);
|
|
521
521
|
delayTimer = null;
|
|
522
522
|
updateTimer = null;
|
|
523
523
|
getPlugin(function (result) {
|
|
@@ -46,7 +46,6 @@ var httpRequest = http.request;
|
|
|
46
46
|
var httpsRequest = https.request;
|
|
47
47
|
var formatHeaders = hparser.formatHeaders;
|
|
48
48
|
var getRawHeaderNames = hparser.getRawHeaderNames;
|
|
49
|
-
var getRawHeaders = hparser.getRawHeaders;
|
|
50
49
|
var STATUS_CODES = http.STATUS_CODES || {};
|
|
51
50
|
var clientIpKey = Symbol('clientIp');
|
|
52
51
|
var clientPortKey = Symbol('clientPort');
|
|
@@ -333,7 +332,7 @@ var pushFrame = function (reqId, data, opts, isClient) {
|
|
|
333
332
|
addFrame(opts);
|
|
334
333
|
};
|
|
335
334
|
var addParserApi = function (req, conn, state, reqId) {
|
|
336
|
-
state
|
|
335
|
+
state.split(',').forEach(function (name) {
|
|
337
336
|
initState(req, name);
|
|
338
337
|
});
|
|
339
338
|
req.on('clientFrame', function (data, opts) {
|
|
@@ -542,7 +541,7 @@ var getOptions = function (opts, binary, toServer) {
|
|
|
542
541
|
var base64ToBuffer = function (base64) {
|
|
543
542
|
if (base64) {
|
|
544
543
|
try {
|
|
545
|
-
return
|
|
544
|
+
return Buffer.from(base64, 'base64');
|
|
546
545
|
} catch (e) {}
|
|
547
546
|
}
|
|
548
547
|
};
|
|
@@ -906,6 +905,9 @@ function wrapTunnelWriter(socket, toServer) {
|
|
|
906
905
|
var write = socket.write;
|
|
907
906
|
var end = socket.end;
|
|
908
907
|
var sender = wsParser.getSender(socket, toServer);
|
|
908
|
+
var notNeedDrain = function() {
|
|
909
|
+
return socket.writableNeedDrain !== true;
|
|
910
|
+
};
|
|
909
911
|
handleError(socket, sender);
|
|
910
912
|
socket.write = function (chunk, encoding, cb) {
|
|
911
913
|
if ((chunk = toBuffer(chunk))) {
|
|
@@ -917,6 +919,7 @@ function wrapTunnelWriter(socket, toServer) {
|
|
|
917
919
|
} else {
|
|
918
920
|
sender.send(chunk);
|
|
919
921
|
}
|
|
922
|
+
return notNeedDrain();
|
|
920
923
|
}
|
|
921
924
|
};
|
|
922
925
|
if (toServer) {
|
|
@@ -926,16 +929,19 @@ function wrapTunnelWriter(socket, toServer) {
|
|
|
926
929
|
return write.call(this, chunk, opts, cb);
|
|
927
930
|
}
|
|
928
931
|
sender.send(chunk, getOptions(opts, false, true));
|
|
932
|
+
return notNeedDrain();
|
|
929
933
|
}
|
|
930
934
|
};
|
|
931
935
|
socket.writeText = function (chunk) {
|
|
932
936
|
if ((chunk = toBuffer(chunk))) {
|
|
933
937
|
sender.send(chunk, getOptions(null, false, true));
|
|
938
|
+
return notNeedDrain();
|
|
934
939
|
}
|
|
935
940
|
};
|
|
936
941
|
socket.writeBin = function (chunk) {
|
|
937
942
|
if ((chunk = toBuffer(chunk))) {
|
|
938
943
|
sender.send(chunk, getOptions(null, true, true));
|
|
944
|
+
return notNeedDrain();
|
|
939
945
|
}
|
|
940
946
|
};
|
|
941
947
|
socket.closeWebSocket = function (code, data, cb) {
|
|
@@ -951,6 +957,7 @@ function wrapTunnelWriter(socket, toServer) {
|
|
|
951
957
|
return write.call(this, chunk, encoding, cb);
|
|
952
958
|
}
|
|
953
959
|
sender.send(chunk);
|
|
960
|
+
return notNeedDrain();
|
|
954
961
|
}
|
|
955
962
|
};
|
|
956
963
|
}
|
|
@@ -1021,6 +1028,9 @@ function addFrameHandler(req, socket, maxWsPayload, fromClient, toServer) {
|
|
|
1021
1028
|
var end = socket.end;
|
|
1022
1029
|
var lastOpts;
|
|
1023
1030
|
var sender = wsParser.getSender(socket, toServer);
|
|
1031
|
+
var notNeedDrain = function() {
|
|
1032
|
+
return socket.writableNeedDrain !== true;
|
|
1033
|
+
};
|
|
1024
1034
|
|
|
1025
1035
|
handleError(socket, sender, receiver);
|
|
1026
1036
|
socket.emit = function (type, chunk) {
|
|
@@ -1042,16 +1052,19 @@ function addFrameHandler(req, socket, maxWsPayload, fromClient, toServer) {
|
|
|
1042
1052
|
return write.call(this, chunk, opts, cb);
|
|
1043
1053
|
}
|
|
1044
1054
|
sender.send(chunk, getOptions(opts || lastOpts, false, toServer));
|
|
1055
|
+
return notNeedDrain();
|
|
1045
1056
|
}
|
|
1046
1057
|
};
|
|
1047
1058
|
socket.writeText = function (chunk) {
|
|
1048
1059
|
if ((chunk = toBuffer(chunk))) {
|
|
1049
1060
|
sender.send(chunk, getOptions(null, false, toServer));
|
|
1061
|
+
return notNeedDrain();
|
|
1050
1062
|
}
|
|
1051
1063
|
};
|
|
1052
1064
|
socket.writeBin = function (chunk) {
|
|
1053
1065
|
if ((chunk = toBuffer(chunk))) {
|
|
1054
1066
|
sender.send(chunk, getOptions(null, true, toServer));
|
|
1067
|
+
return notNeedDrain();
|
|
1055
1068
|
}
|
|
1056
1069
|
};
|
|
1057
1070
|
socket.end = function (chunk, opts, cb) {
|
|
@@ -2253,11 +2266,9 @@ module.exports = async function (options, callback) {
|
|
|
2253
2266
|
socket.setRules = req.setResRules = socket.setResRules = noop;
|
|
2254
2267
|
resRules = null;
|
|
2255
2268
|
}
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
}
|
|
2260
|
-
socket.write(rawData + '\r\n\r\n', 'binary');
|
|
2269
|
+
headers = headers && formatRawHeaders(headers, svrRes);
|
|
2270
|
+
msg = msg || svrRes.statusMessage || STATUS_CODES[code] || '';
|
|
2271
|
+
socket.write(common.getHttpMeta('HTTP/1.1', code, msg, headers), 'binary');
|
|
2261
2272
|
};
|
|
2262
2273
|
req.request = function (uri, cb, opts) {
|
|
2263
2274
|
var args = normalizeArgs(uri, cb, req, curUrl, true, opts);
|
package/lib/rules/util.js
CHANGED
|
@@ -166,14 +166,19 @@ function unselectRulesFile(file, force, all) {
|
|
|
166
166
|
}
|
|
167
167
|
var selectedList = getSelectedRulesList();
|
|
168
168
|
var hasChanged;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
169
|
+
if (file === false) {
|
|
170
|
+
hasChanged = selectedList.length;
|
|
171
|
+
selectedList = [];
|
|
172
|
+
} else {
|
|
173
|
+
all = all || [file];
|
|
174
|
+
all.forEach(function(name) {
|
|
175
|
+
var index = selectedList.indexOf(name);
|
|
176
|
+
if (index != -1) {
|
|
177
|
+
selectedList.splice(index, 1);
|
|
178
|
+
hasChanged = true;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
177
182
|
if (hasChanged) {
|
|
178
183
|
rulesStorage.setProperty('selectedList', selectedList);
|
|
179
184
|
parseRules();
|
|
@@ -185,7 +190,7 @@ function unselectRulesFile(file, force, all) {
|
|
|
185
190
|
function allowMultipleChoice() {
|
|
186
191
|
return (
|
|
187
192
|
!config.disabledMultipleOption &&
|
|
188
|
-
propertiesStorage.getProperty('allowMultipleChoice')
|
|
193
|
+
!!propertiesStorage.getProperty('allowMultipleChoice')
|
|
189
194
|
);
|
|
190
195
|
}
|
|
191
196
|
|
|
@@ -290,8 +295,10 @@ exports.rules = {
|
|
|
290
295
|
}
|
|
291
296
|
});
|
|
292
297
|
return {
|
|
298
|
+
laterRulesFirst: propertiesStorage.getProperty('backRulesFirst') === true,
|
|
293
299
|
pluginsDisabled: propertiesStorage.getProperty('disabledAllPlugins'),
|
|
294
300
|
disabled: !config.notAllowedDisableRules && propertiesStorage.getProperty('disabledAllRules'),
|
|
301
|
+
multiSelect: allowMultipleChoice(),
|
|
295
302
|
list: list
|
|
296
303
|
};
|
|
297
304
|
},
|
|
@@ -320,6 +327,9 @@ exports.rules = {
|
|
|
320
327
|
exists: function(name) {
|
|
321
328
|
return rulesStorage.existsFile(name);
|
|
322
329
|
},
|
|
330
|
+
isSelected: function(name) {
|
|
331
|
+
return getSelectedRulesList().indexOf(name) !== -1;
|
|
332
|
+
},
|
|
323
333
|
recycleBin: rulesStorage.recycleBin,
|
|
324
334
|
enableBackRulesFirst: function (backRulesFirst) {
|
|
325
335
|
var curFlag = propertiesStorage.getProperty('backRulesFirst') === true;
|
|
@@ -338,7 +348,7 @@ exports.rules = {
|
|
|
338
348
|
});
|
|
339
349
|
return {
|
|
340
350
|
backRulesFirst: propertiesStorage.getProperty('backRulesFirst') === true,
|
|
341
|
-
allowMultipleChoice:
|
|
351
|
+
allowMultipleChoice: allowMultipleChoice(),
|
|
342
352
|
list: list
|
|
343
353
|
};
|
|
344
354
|
},
|
package/lib/service/composer.js
CHANGED
|
@@ -11,7 +11,6 @@ var Storage = require('../rules/storage');
|
|
|
11
11
|
var dataCenter = require('./data-center');
|
|
12
12
|
|
|
13
13
|
var formatHeaders = hparser.formatHeaders;
|
|
14
|
-
var getRawHeaders = hparser.getRawHeaders;
|
|
15
14
|
var getRawHeaderNames = hparser.getRawHeaderNames;
|
|
16
15
|
var config = {};
|
|
17
16
|
var noop = common.noop;
|
|
@@ -68,10 +67,8 @@ function handleComposerHistory(data, isConn) {
|
|
|
68
67
|
body: body.length > MAX_BODY_LEN ? body.substring(0, MAX_BODY_LEN) : body,
|
|
69
68
|
isHexText: !!data.isHexText,
|
|
70
69
|
base64: base64,
|
|
71
|
-
enableProxyRules:
|
|
70
|
+
enableProxyRules: data.enableProxyRules
|
|
72
71
|
};
|
|
73
|
-
var dataHash;
|
|
74
|
-
var base64Hash;
|
|
75
72
|
for (var i = 0, len = composerHistory.length; i < len; i++) {
|
|
76
73
|
var item = composerHistory[i];
|
|
77
74
|
if (
|
|
@@ -81,16 +78,12 @@ function handleComposerHistory(data, isConn) {
|
|
|
81
78
|
item.body === result.body &&
|
|
82
79
|
item.base64 === result.base64 &&
|
|
83
80
|
!item.useH2 !== result.useH2 &&
|
|
84
|
-
|
|
81
|
+
item.enableProxyRules === result.enableProxyRules
|
|
85
82
|
) {
|
|
86
|
-
dataHash = item.dataHash;
|
|
87
|
-
base64Hash = item.base64Hash;
|
|
88
83
|
composerHistory.splice(i, 1);
|
|
89
84
|
break;
|
|
90
85
|
}
|
|
91
86
|
}
|
|
92
|
-
result.dataHash = dataHash;
|
|
93
|
-
result.base64Hash = base64Hash;
|
|
94
87
|
composerHistory.unshift(result);
|
|
95
88
|
var overflow = composerHistory.length - MAX_HISTORY_LEN;
|
|
96
89
|
if (overflow > 0) {
|
|
@@ -183,16 +176,6 @@ function handleConnect(options, cb, count, testId) {
|
|
|
183
176
|
}
|
|
184
177
|
}
|
|
185
178
|
|
|
186
|
-
function getReqRaw(options) {
|
|
187
|
-
var headers = options.headers;
|
|
188
|
-
var statusLine = options.method +' ' + (options.path || '/') +' ' + 'HTTP/1.1';
|
|
189
|
-
var raw = statusLine;
|
|
190
|
-
if (headers = getRawHeaders(headers)) {
|
|
191
|
-
raw += '\r\n' + headers;
|
|
192
|
-
}
|
|
193
|
-
return raw + '\r\n\r\n';
|
|
194
|
-
}
|
|
195
|
-
|
|
196
179
|
function handleWebSocket(options, cb, count, testId) {
|
|
197
180
|
count = getReqCount(count);
|
|
198
181
|
if (options.protocol === 'https:' || options.protocol === 'wss:') {
|
|
@@ -213,7 +196,7 @@ function handleWebSocket(options, cb, count, testId) {
|
|
|
213
196
|
if (err) {
|
|
214
197
|
handleCallback(execCb, err, null, testId);
|
|
215
198
|
} else {
|
|
216
|
-
socket.write(
|
|
199
|
+
socket.write(common.getHttpMeta(options.method, options.path || '/', 'HTTP/1.1', options.headers));
|
|
217
200
|
var data = options.body;
|
|
218
201
|
if ((!data || !data.length) && !cb) {
|
|
219
202
|
return drain(socket);
|
|
@@ -293,7 +276,7 @@ function handleHttp(options, cb, count, reqId, testId) {
|
|
|
293
276
|
if (buffer === null) {
|
|
294
277
|
return;
|
|
295
278
|
}
|
|
296
|
-
|
|
279
|
+
clearTimeout(timer);
|
|
297
280
|
var headers = svrRes.headers;
|
|
298
281
|
if (typeof headers.trailer === 'string' && headers.trailer.indexOf(',') !== -1) {
|
|
299
282
|
headers.trailer = headers.trailer.split(',');
|
|
@@ -397,7 +380,9 @@ exports.handleRequest = function(req, res) {
|
|
|
397
380
|
headers[config.FROM_COM_HEADER] = '1';
|
|
398
381
|
var isTest = reqBody.isTest;
|
|
399
382
|
var testId;
|
|
400
|
-
|
|
383
|
+
var enableProxyRules = reqBody.enableProxyRules !== false && !reqBody.disabledGlobalRules;
|
|
384
|
+
reqBody.enableProxyRules = enableProxyRules;
|
|
385
|
+
if (!enableProxyRules || isTest) {
|
|
401
386
|
headers[config.DISABLE_RULES_HEADER] = '1';
|
|
402
387
|
if (isTest) {
|
|
403
388
|
testId = ++testIndex + '';
|