whistle 2.10.2 → 2.10.4
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 -0
- package/assets/modal.html +2 -0
- package/assets/tab.html +3 -3
- package/bin/proxy.js +2 -2
- package/bin/whistle.js +5 -5
- 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/download.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 +7 -0
- 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/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 +54 -52
- package/biz/webui/lib/index.js +32 -2
- package/lib/config.js +4 -4
- package/lib/handlers/file-proxy.js +1 -1
- package/lib/https/ca.js +31 -0
- package/lib/https/index.js +4 -2
- package/lib/index.js +0 -2
- package/lib/inspectors/data.js +120 -13
- package/lib/inspectors/req.js +5 -3
- package/lib/plugins/get-plugins-sync.js +15 -11
- package/lib/plugins/get-plugins.js +11 -12
- package/lib/plugins/load-plugin.js +1 -1
- package/lib/plugins/module-paths.js +4 -0
- package/lib/plugins/util.js +8 -0
- package/lib/rules/dns.js +4 -0
- package/lib/rules/rules.js +7 -8
- package/lib/service/composer.js +86 -39
- package/lib/service/service.js +14 -10
- package/lib/service/util.js +3 -42
- package/lib/socket-mgr.js +2 -16
- package/lib/tunnel.js +3 -0
- package/lib/upgrade.js +1 -0
- package/lib/util/common.js +54 -10
- package/lib/util/data-server.js +10 -0
- package/lib/util/index.js +38 -19
- package/package.json +2 -2
- package/biz/webui/cgi-bin/import-remote.js +0 -37
package/biz/webui/lib/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var common = require('../../../lib/util/common');
|
|
|
20
20
|
var getWorker = require('../../../lib/plugins/util').getWorker;
|
|
21
21
|
var loadAuthPlugins = require('../../../lib/plugins').loadAuthPlugins;
|
|
22
22
|
var parseUrl = require('../../../lib/util/parse-url-safe');
|
|
23
|
+
var loadService = require('../../../lib/service');
|
|
23
24
|
|
|
24
25
|
var sendError = cgiUtil.sendError;
|
|
25
26
|
var sendGzipText = cgiUtil.sendGzipText;
|
|
@@ -55,6 +56,8 @@ var MENU_URL = '???_WHISTLE_PLUGIN_EXT_CONTEXT_MENU_' + config.port + '???';
|
|
|
55
56
|
var INSPECTOR_URL = '???_WHISTLE_PLUGIN_INSPECTOR_TAB_' + config.port + '???';
|
|
56
57
|
var KEY_RE_G = /\${[^{}\s]+}|{\S+}/g;
|
|
57
58
|
var COMMENT_RE = /#[^\r\n]*$/mg;
|
|
59
|
+
var MAX_LEN = 1024 * 1024 * 6;
|
|
60
|
+
var HTTP_RE = /https?:\/\/\S/i;
|
|
58
61
|
|
|
59
62
|
function hasLogin() {
|
|
60
63
|
return config.username && config.password;
|
|
@@ -65,7 +68,7 @@ function isTempFile(query) {
|
|
|
65
68
|
if (files && typeof files === 'string') {
|
|
66
69
|
return false;
|
|
67
70
|
}
|
|
68
|
-
return common.
|
|
71
|
+
return common.getTempFile(query.filename);
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
function sendToService(req, res) {
|
|
@@ -74,10 +77,11 @@ function sendToService(req, res) {
|
|
|
74
77
|
res.end('{"ec":0,"value":"","forbidden":true}');
|
|
75
78
|
return;
|
|
76
79
|
}
|
|
77
|
-
|
|
80
|
+
loadService(function(err, options) {
|
|
78
81
|
if (err) {
|
|
79
82
|
common.sendRes(res, 500, err.stack || err);
|
|
80
83
|
} else {
|
|
84
|
+
req.headers[common.WHISTLE_UID_HEADER] = config.uid;
|
|
81
85
|
util.transformReq(req, res, options.port);
|
|
82
86
|
}
|
|
83
87
|
});
|
|
@@ -407,6 +411,32 @@ function cgiHandler(req, res) {
|
|
|
407
411
|
handleResponse();
|
|
408
412
|
});
|
|
409
413
|
}
|
|
414
|
+
app.get('/cgi-bin/import-remote', function(req, res) {
|
|
415
|
+
var url = req.query.url;
|
|
416
|
+
if (HTTP_RE.test(url)) {
|
|
417
|
+
util.request({
|
|
418
|
+
url: url,
|
|
419
|
+
maxLength: MAX_LEN
|
|
420
|
+
}, function(err, body, r) {
|
|
421
|
+
if (err) {
|
|
422
|
+
var msg = err.code === 'EEXCEED' ? 'The size of response body exceeds 6MB' : err.message;
|
|
423
|
+
return res.json({ec: 2, em: msg});
|
|
424
|
+
}
|
|
425
|
+
var status = r.statusCode;
|
|
426
|
+
if (status !== 200) {
|
|
427
|
+
var em = status > 200 && status < 400 ? 'No data' : 'Request failed';
|
|
428
|
+
return res.json({ec: 2, em: em + ' (statusCode: ' + status + ')'});
|
|
429
|
+
}
|
|
430
|
+
return res.json({ec: 0, body: body});
|
|
431
|
+
});
|
|
432
|
+
} else if (util.isString(url)) {
|
|
433
|
+
req.url = '/cgi-bin/temp/get?filename=' + encodeURIComponent(url);
|
|
434
|
+
req.query.filename = url;
|
|
435
|
+
sendToService(req, res);
|
|
436
|
+
} else {
|
|
437
|
+
res.json({ec: 400, em: 'Bad url'});
|
|
438
|
+
}
|
|
439
|
+
});
|
|
410
440
|
app.all('/service/*', sendToService);
|
|
411
441
|
app.all('/cgi-bin/service/*', sendToService);
|
|
412
442
|
app.all('/cgi-bin/sessions/*', sendToService);
|
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,
|
|
@@ -148,7 +149,6 @@ function getDataDir(dirname) {
|
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
config.baseDir = getDataDir();
|
|
151
|
-
config.TEMP_FILES_PATH = path.join(getWhistlePath(), 'temp_files');
|
|
152
152
|
config.CUSTOM_PLUGIN_PATH = path.join(getWhistlePath(), 'custom_plugins');
|
|
153
153
|
config.CUSTOM_CERTS_DIR = path.resolve(getWhistlePath(), 'custom_certs');
|
|
154
154
|
config.SAVED_SESSIONS_PATH = path.resolve(getWhistlePath(), 'saved_sessions');
|
|
@@ -158,8 +158,8 @@ config.valuesDir = path.join(config.baseDir, 'values');
|
|
|
158
158
|
config.propertiesDir = path.join(config.baseDir, 'properties');
|
|
159
159
|
|
|
160
160
|
try {
|
|
161
|
-
fse.ensureDirSync(
|
|
162
|
-
var blankFile = path.join(
|
|
161
|
+
fse.ensureDirSync(common.TEMP_FILES_PATH);
|
|
162
|
+
var blankFile = path.join(common.TEMP_FILES_PATH, 'blank');
|
|
163
163
|
if (!fs.existsSync(blankFile)) {
|
|
164
164
|
fs.writeFileSync(blankFile, '');
|
|
165
165
|
}
|
|
@@ -796,7 +796,7 @@ exports.extend = function (newConf) {
|
|
|
796
796
|
setDefaultResultOrder(m.toLowerCase());
|
|
797
797
|
} else if (m === 'proxyOnly') {
|
|
798
798
|
config.pureProxy = true;
|
|
799
|
-
} else if (m === 'useMultipleRules' || m === 'enableMultipleRules') {
|
|
799
|
+
} else if (m === 'useMultipleRules' || m === 'enableMultipleRules' || m === 'allowMultipleChoice') {
|
|
800
800
|
config.allowMultipleChoice = true;
|
|
801
801
|
} else if (m === 'disableMultipleRules') {
|
|
802
802
|
config.allowMultipleChoice = false;
|
|
@@ -66,7 +66,7 @@ function parseRes(str, rawHeaderNames, fromValue) {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
var headers = str.split(CRLF_RE);
|
|
69
|
-
var statusLine = headers.shift().trim().split(/\s+/
|
|
69
|
+
var statusLine = headers.shift().trim().split(/\s+/);
|
|
70
70
|
headers = util.parseHeaders(headers, rawHeaderNames);
|
|
71
71
|
if (fromValue) {
|
|
72
72
|
delete headers['content-encoding'];
|
package/lib/https/ca.js
CHANGED
|
@@ -177,6 +177,19 @@ exports.hasCustomCerts = function () {
|
|
|
177
177
|
return customCertCount;
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
+
var rootSkiBytes;
|
|
181
|
+
|
|
182
|
+
function getRootSKI() {
|
|
183
|
+
if (!rootSkiBytes) {
|
|
184
|
+
try {
|
|
185
|
+
rootSkiBytes = ROOT_CRT.generateSubjectKeyIdentifier().getBytes();
|
|
186
|
+
} catch (e) {
|
|
187
|
+
rootSkiBytes = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return rootSkiBytes;
|
|
191
|
+
}
|
|
192
|
+
|
|
180
193
|
function getCacheCert(hostname) {
|
|
181
194
|
return (
|
|
182
195
|
customPairs[hostname] ||
|
|
@@ -206,6 +219,20 @@ function createSelfCert(hostname) {
|
|
|
206
219
|
]);
|
|
207
220
|
cert.setIssuer(ROOT_CRT.subject.attributes);
|
|
208
221
|
cert.setExtensions([
|
|
222
|
+
{
|
|
223
|
+
name: 'basicConstraints',
|
|
224
|
+
cA: false
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'keyUsage',
|
|
228
|
+
digitalSignature: true,
|
|
229
|
+
keyEncipherment: true
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'extKeyUsage',
|
|
233
|
+
serverAuth: true,
|
|
234
|
+
clientAuth: true
|
|
235
|
+
},
|
|
209
236
|
{
|
|
210
237
|
name: 'subjectAltName',
|
|
211
238
|
altNames: [
|
|
@@ -219,6 +246,10 @@ function createSelfCert(hostname) {
|
|
|
219
246
|
value: hostname
|
|
220
247
|
}
|
|
221
248
|
]
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: 'authorityKeyIdentifier',
|
|
252
|
+
keyIdentifier: getRootSKI() // Get SKI from ROOT_CRT for authorityKeyIdentifier extension
|
|
222
253
|
}
|
|
223
254
|
]);
|
|
224
255
|
cert.sign(ROOT_KEY, forge.md.sha256.create());
|
package/lib/https/index.js
CHANGED
|
@@ -106,6 +106,7 @@ function resolveWebsocket(socket, wss) {
|
|
|
106
106
|
_clientId: socket._clientId,
|
|
107
107
|
id: socket.reqId,
|
|
108
108
|
fc: socket.fromComposer ? 1 : undefined,
|
|
109
|
+
testId: socket._testId,
|
|
109
110
|
url: fullUrl,
|
|
110
111
|
startTime: now,
|
|
111
112
|
sniPlugin: socket.sniPlugin,
|
|
@@ -718,9 +719,10 @@ function resolveWebsocket(socket, wss) {
|
|
|
718
719
|
extend(headers, reqHeaders);
|
|
719
720
|
headers.host = headers.host || host;
|
|
720
721
|
}
|
|
721
|
-
|
|
722
|
+
authObj = auth || authObj;
|
|
723
|
+
auth = util.getAuthBasic(authObj);
|
|
722
724
|
if (auth) {
|
|
723
|
-
headers['authorization'] = auth;
|
|
725
|
+
headers[(authObj.proxy ? 'proxy-' : '') + 'authorization'] = auth;
|
|
724
726
|
}
|
|
725
727
|
var reqRuleData = { headers: headers };
|
|
726
728
|
util.setReqCors(reqRuleData, reqCors);
|
package/lib/index.js
CHANGED
|
@@ -13,7 +13,6 @@ var rulesUtil = require('./rules/util');
|
|
|
13
13
|
var initDataServer = require('./util/data-server');
|
|
14
14
|
var pluginMgr = require('./plugins');
|
|
15
15
|
var config = require('./config');
|
|
16
|
-
var loadService = require('./service');
|
|
17
16
|
var initSocketMgr = require('./socket-mgr');
|
|
18
17
|
var tunnelProxy = require('./tunnel');
|
|
19
18
|
var upgradeProxy = require('./upgrade');
|
|
@@ -222,7 +221,6 @@ function exportInterfaces(obj) {
|
|
|
222
221
|
obj.httpsUtil = httpsUtil;
|
|
223
222
|
obj.pluginMgr = pluginMgr;
|
|
224
223
|
obj.logger = logger;
|
|
225
|
-
obj.loadService = loadService;
|
|
226
224
|
obj.setAuth = config.setAuth;
|
|
227
225
|
obj.setUIHost = config.setUIHost;
|
|
228
226
|
obj.setPluginUIHost = config.setPluginUIHost;
|
package/lib/inspectors/data.js
CHANGED
|
@@ -10,7 +10,9 @@ var MAX_REQ_BODY_SIZE = (config.strict ? 256 : 2048) * 1024;
|
|
|
10
10
|
var MAX_RES_BODY_SIZE = (config.strict ? 256 : 2048) * 1024;
|
|
11
11
|
var BIG_DATA_SIZE = 1024 * 1024 * 16;
|
|
12
12
|
var LOCALHOST = '127.0.0.1';
|
|
13
|
-
var
|
|
13
|
+
var MAX_PAYLOAD = util.MAX_FRAME_PAYLOAD;
|
|
14
|
+
var SSE_SEP = Buffer.from('\n\n');
|
|
15
|
+
var FRAME_SEP_KEY = 'x-whistle-custom-frame-separator';
|
|
14
16
|
|
|
15
17
|
function getZipType(options) {
|
|
16
18
|
return options.headers && options.headers['content-encoding'];
|
|
@@ -57,6 +59,80 @@ function emitDataEvents(req, res, proxy) {
|
|
|
57
59
|
if (!util.showPluginReq(req) || util.isHide(req)) {
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
62
|
+
|
|
63
|
+
var reqSepInfo = parseFrameSep(req.headers);
|
|
64
|
+
var cseSep = reqSepInfo && reqSepInfo.sep;
|
|
65
|
+
var resSepInfo;
|
|
66
|
+
|
|
67
|
+
function emitFrame(chunk, fromServer) {
|
|
68
|
+
proxy.emit('frame', {
|
|
69
|
+
reqId: req.reqId,
|
|
70
|
+
frameId: util.getFrameId(),
|
|
71
|
+
isClient: !fromServer,
|
|
72
|
+
length: chunk.length,
|
|
73
|
+
bin: chunk
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function parseFrameSep(headers) {
|
|
78
|
+
var sep = headers[FRAME_SEP_KEY];
|
|
79
|
+
if (!util.isString(sep)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
var result = {};
|
|
83
|
+
delete headers[FRAME_SEP_KEY];
|
|
84
|
+
try {
|
|
85
|
+
sep = decodeURIComponent(sep);
|
|
86
|
+
} catch (e) {}
|
|
87
|
+
if (sep[0] === '/') {
|
|
88
|
+
result.keepSep = true;
|
|
89
|
+
sep = sep.slice(1);
|
|
90
|
+
}
|
|
91
|
+
if (sep) {
|
|
92
|
+
result.sep = Buffer.from(sep);
|
|
93
|
+
result.sepLen = sep.length;
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function parseFrame(buf, isRes, end) {
|
|
99
|
+
var len = buf && buf.length;
|
|
100
|
+
if (!len) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
var sep, sepLen, keepSep;
|
|
104
|
+
var info = isRes ? resSepInfo : reqSepInfo;
|
|
105
|
+
if (info) {
|
|
106
|
+
sep = info.sep;
|
|
107
|
+
sepLen = info.sepLen;
|
|
108
|
+
keepSep = info.keepSep;
|
|
109
|
+
} else {
|
|
110
|
+
sep = SSE_SEP;
|
|
111
|
+
sepLen = 2;
|
|
112
|
+
}
|
|
113
|
+
var index = buf.indexOf(sep);
|
|
114
|
+
while (index !== -1) {
|
|
115
|
+
if (keepSep) {
|
|
116
|
+
index += sepLen;
|
|
117
|
+
}
|
|
118
|
+
index && emitFrame(buf.slice(0, index), isRes);
|
|
119
|
+
buf = buf.slice(keepSep ? index : index + sepLen);
|
|
120
|
+
index = buf.indexOf(sep);
|
|
121
|
+
}
|
|
122
|
+
len = buf.length;
|
|
123
|
+
if (!len) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
if (end) {
|
|
127
|
+
emitFrame(buf, isRes);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
if (len > MAX_PAYLOAD) {
|
|
131
|
+
emitFrame(buf.slice(0, -1), isRes);
|
|
132
|
+
buf = buf.slice(-1);
|
|
133
|
+
}
|
|
134
|
+
return buf;
|
|
135
|
+
}
|
|
60
136
|
var getTTFB = function () {
|
|
61
137
|
if (req._ttfb >= now) {
|
|
62
138
|
return req._ttfb - now;
|
|
@@ -82,6 +158,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
82
158
|
h2Id: req._alpn,
|
|
83
159
|
fc: req.fromComposer ? 1 : undefined,
|
|
84
160
|
isPR: req.isPluginReq ? 1 : undefined,
|
|
161
|
+
testId: req._testId,
|
|
85
162
|
_clientId: req._clientId,
|
|
86
163
|
startTime: now,
|
|
87
164
|
ttfb: getTTFB(),
|
|
@@ -167,12 +244,20 @@ function emitDataEvents(req, res, proxy) {
|
|
|
167
244
|
var captureReqStream;
|
|
168
245
|
var maxReqSize;
|
|
169
246
|
var reqInfo;
|
|
247
|
+
var setReqBody = function (body, end) {
|
|
248
|
+
if (captureReqStream && cseSep) {
|
|
249
|
+
reqBody = parseFrame(reqBody, false, end);
|
|
250
|
+
} else {
|
|
251
|
+
reqData.body = reqBody;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
170
254
|
var updateReqInfo = function() {
|
|
171
255
|
if (reqInfo && !captureReqStream) {
|
|
172
256
|
captureReqStream = !disable.captureStream && (resDone || enable.captureStream) && !getZipType(reqInfo);
|
|
173
257
|
maxReqSize = useBigData ? BIG_DATA_SIZE : (captureReqStream ? MAX_REQ_BODY_SIZE : MAX_SIZE);
|
|
174
|
-
if (captureReqStream
|
|
175
|
-
|
|
258
|
+
if (captureReqStream) {
|
|
259
|
+
data.isCse = !!cseSep;
|
|
260
|
+
reqBody && !reqData.body && setReqBody(reqBody);
|
|
176
261
|
}
|
|
177
262
|
}
|
|
178
263
|
};
|
|
@@ -198,7 +283,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
198
283
|
} else {
|
|
199
284
|
reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
|
|
200
285
|
if (captureReqStream) {
|
|
201
|
-
|
|
286
|
+
setReqBody(reqBody);
|
|
202
287
|
}
|
|
203
288
|
if (reqBody.length > maxReqSize) {
|
|
204
289
|
reqBody = false;
|
|
@@ -225,8 +310,8 @@ function emitDataEvents(req, res, proxy) {
|
|
|
225
310
|
data.endTime = endTime;
|
|
226
311
|
}
|
|
227
312
|
reqBody = err ? util.getErrorStack(err) : body;
|
|
228
|
-
|
|
229
|
-
setUnzipSize(body, reqData);
|
|
313
|
+
setReqBody(reqBody, true);
|
|
314
|
+
!data.isCse && setUnzipSize(body, reqData);
|
|
230
315
|
checkBodySize(reqData, useBigData);
|
|
231
316
|
});
|
|
232
317
|
updateEvent && proxy.emit(updateEvent, req.fullUrl, false, true);
|
|
@@ -239,9 +324,22 @@ function emitDataEvents(req, res, proxy) {
|
|
|
239
324
|
}
|
|
240
325
|
resDone = true;
|
|
241
326
|
info = info || (res._needGunzip ? { statusCode: res.statusCode, headers: '' } : res);
|
|
242
|
-
var
|
|
243
|
-
|
|
327
|
+
var isSse;
|
|
328
|
+
var captureStream;
|
|
329
|
+
if (!disable.captureStream && !getZipType(info)) {
|
|
330
|
+
var headers = info.headers;
|
|
331
|
+
captureStream = requestTime == null || enable.captureStream;
|
|
332
|
+
if (headers) {
|
|
333
|
+
isSse = headers['content-type'] === 'text/event-stream';
|
|
334
|
+
captureStream = captureStream || isSse;
|
|
335
|
+
resSepInfo = parseFrameSep(headers);
|
|
336
|
+
if (resSepInfo && resSepInfo.sep) {
|
|
337
|
+
isSse = captureStream;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
244
341
|
var maxResSize = useBigData ? BIG_DATA_SIZE : (captureStream ? MAX_RES_BODY_SIZE : MAX_SIZE);
|
|
342
|
+
data.isSse = isSse;
|
|
245
343
|
captureStream && updateReqInfo();
|
|
246
344
|
if (!cleared && util.hasBody(info, req) && checkType(info)) {
|
|
247
345
|
if (info.headers['content-length'] > maxResSize && !captureStream) {
|
|
@@ -261,9 +359,13 @@ function emitDataEvents(req, res, proxy) {
|
|
|
261
359
|
} else {
|
|
262
360
|
resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
|
|
263
361
|
if (captureStream) {
|
|
264
|
-
|
|
362
|
+
if (isSse) {
|
|
363
|
+
resBody = parseFrame(resBody, true);
|
|
364
|
+
} else {
|
|
365
|
+
resData.body = resBody;
|
|
366
|
+
}
|
|
265
367
|
}
|
|
266
|
-
if (resBody.length > maxResSize) {
|
|
368
|
+
if (resBody && resBody.length > maxResSize) {
|
|
267
369
|
resBody = false;
|
|
268
370
|
}
|
|
269
371
|
}
|
|
@@ -286,9 +388,13 @@ function emitDataEvents(req, res, proxy) {
|
|
|
286
388
|
resData.hasGzipError = unzipBody(info, resBody, function (err, body) {
|
|
287
389
|
if (!data.resError) {
|
|
288
390
|
resBody = err ? util.getErrorStack(err) : body;
|
|
289
|
-
|
|
391
|
+
if (isSse) {
|
|
392
|
+
resBody = parseFrame(resBody, true, true);
|
|
393
|
+
} else {
|
|
394
|
+
resData.body = resBody;
|
|
395
|
+
}
|
|
290
396
|
}
|
|
291
|
-
setUnzipSize(body, resData);
|
|
397
|
+
!isSse && setUnzipSize(body, resData);
|
|
292
398
|
checkBodySize(resData, useBigData);
|
|
293
399
|
setEndTime();
|
|
294
400
|
reqEmitter.emit('end', data);
|
|
@@ -341,7 +447,8 @@ function emitDataEvents(req, res, proxy) {
|
|
|
341
447
|
}
|
|
342
448
|
!endTime && setEndTime();
|
|
343
449
|
delete data.abort;
|
|
344
|
-
|
|
450
|
+
var msg = err && err.message;
|
|
451
|
+
if (msg !== 'Aborted') {
|
|
345
452
|
data.resError = true;
|
|
346
453
|
if (resData.body) {
|
|
347
454
|
data.errMsg = util.getErrorStack(err);
|
package/lib/inspectors/req.js
CHANGED
|
@@ -147,9 +147,11 @@ function handleReq(req, data, reqRules, delType) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
function handleAuth(data,
|
|
151
|
-
auth = util.getAuthBasic(
|
|
152
|
-
|
|
150
|
+
function handleAuth(data, authObj) {
|
|
151
|
+
var auth = util.getAuthBasic(authObj);
|
|
152
|
+
if (auth) {
|
|
153
|
+
util.setHeader(data, (authObj.proxy ? 'proxy-' : '') + 'authorization', auth);
|
|
154
|
+
}
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
function handleParams(req, params, urlParams, enableBigData) {
|
|
@@ -12,6 +12,7 @@ var notUninstallPluginPaths = config.notUninstallPluginPaths || [];
|
|
|
12
12
|
var projectPluginPaths = config.projectPluginPaths || [];
|
|
13
13
|
var accountPluginsPath = config.accountPluginsPath || [];
|
|
14
14
|
var paths = mp.getPaths();
|
|
15
|
+
var PLUGIN_DIR = pluginUtil.PLUGIN_DIR;
|
|
15
16
|
|
|
16
17
|
function getMTimeSync(filePath) {
|
|
17
18
|
var stats = common.getStatSync(filePath);
|
|
@@ -41,8 +42,9 @@ function readPluginModulesSync(dir, plugins) {
|
|
|
41
42
|
var mtime = getMTimeSync(path.join(root, 'package.json'));
|
|
42
43
|
if (mtime != null) {
|
|
43
44
|
var old = plugins[name];
|
|
44
|
-
if (
|
|
45
|
+
if (pluginUtil.compparePlugin(dir, mtime, old)) {
|
|
45
46
|
plugins[name] = {
|
|
47
|
+
[PLUGIN_DIR]: dir,
|
|
46
48
|
mtime: mtime,
|
|
47
49
|
root: root,
|
|
48
50
|
account: account,
|
|
@@ -65,8 +67,9 @@ function readPluginModulesSync(dir, plugins) {
|
|
|
65
67
|
var mtime = getMTimeSync(path.join(root, 'package.json'));
|
|
66
68
|
if (mtime != null) {
|
|
67
69
|
var old = plugins[name];
|
|
68
|
-
if (
|
|
70
|
+
if (pluginUtil.compparePlugin(dir, mtime, old)) {
|
|
69
71
|
plugins[name] = {
|
|
72
|
+
[PLUGIN_DIR]: dir,
|
|
70
73
|
root: root,
|
|
71
74
|
mtime: mtime,
|
|
72
75
|
account: account,
|
|
@@ -95,15 +98,15 @@ module.exports = function () {
|
|
|
95
98
|
if (pluginUtil.excludePlugin(simpleName)) {
|
|
96
99
|
return;
|
|
97
100
|
}
|
|
98
|
-
var
|
|
99
|
-
var account =
|
|
100
|
-
var isSys =
|
|
101
|
-
var isProj =
|
|
102
|
-
var notUn =
|
|
103
|
-
var isDev =
|
|
104
|
-
var dirName =
|
|
105
|
-
var mtime =
|
|
106
|
-
dir =
|
|
101
|
+
var obj = plugins[name];
|
|
102
|
+
var account = obj.account;
|
|
103
|
+
var isSys = obj.isSys;
|
|
104
|
+
var isProj = obj.isProj;
|
|
105
|
+
var notUn = obj.notUn;
|
|
106
|
+
var isDev = obj.isDev;
|
|
107
|
+
var dirName = obj.dir;
|
|
108
|
+
var mtime = obj.mtime;
|
|
109
|
+
var dir = obj.root;
|
|
107
110
|
var pkgPath = path.join(dir, 'package.json');
|
|
108
111
|
var pkg = common.readJsonSync(pkgPath);
|
|
109
112
|
if (!pkg) {
|
|
@@ -120,6 +123,7 @@ module.exports = function () {
|
|
|
120
123
|
var tabs = util.getInspectorTabs(conf);
|
|
121
124
|
var hintList = util.getHintList(conf);
|
|
122
125
|
var plugin = {
|
|
126
|
+
[PLUGIN_DIR]: obj[PLUGIN_DIR],
|
|
123
127
|
account: account,
|
|
124
128
|
dir: dirName,
|
|
125
129
|
isSys: isSys,
|
|
@@ -9,6 +9,7 @@ var customPluginPaths = config.customPluginPaths || [];
|
|
|
9
9
|
var notUninstallPluginPaths = config.notUninstallPluginPaths || [];
|
|
10
10
|
var projectPluginPaths = config.projectPluginPaths || [];
|
|
11
11
|
var accountPluginsPath = config.accountPluginsPath || [];
|
|
12
|
+
var PLUGIN_DIR = pluginUtil.PLUGIN_DIR;
|
|
12
13
|
|
|
13
14
|
function readPluginRootList(dir, callback) {
|
|
14
15
|
var roots = [];
|
|
@@ -31,7 +32,7 @@ function readPluginRootList(dir, callback) {
|
|
|
31
32
|
if (pluginUtil.isWhistleModule(name)) {
|
|
32
33
|
roots[i] = {
|
|
33
34
|
name: name,
|
|
34
|
-
|
|
35
|
+
[PLUGIN_DIR]: dir
|
|
35
36
|
};
|
|
36
37
|
} else if (pluginUtil.isOrgModule(name)) {
|
|
37
38
|
++count;
|
|
@@ -44,7 +45,7 @@ function readPluginRootList(dir, callback) {
|
|
|
44
45
|
orgList.push({
|
|
45
46
|
org: name,
|
|
46
47
|
name: pluginName,
|
|
47
|
-
|
|
48
|
+
[PLUGIN_DIR]: dir
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
});
|
|
@@ -74,7 +75,7 @@ function readPluginModules(dir, callback, plugins, isSys) {
|
|
|
74
75
|
return callback(plugins);
|
|
75
76
|
}
|
|
76
77
|
list.forEach(function (obj) {
|
|
77
|
-
var dir = obj
|
|
78
|
+
var dir = obj[PLUGIN_DIR];
|
|
78
79
|
var dirName = obj.org ? obj.org + '/' + obj.name : obj.name;
|
|
79
80
|
pluginUtil.getSysPath(dir, dirName, isSys, function(root) {
|
|
80
81
|
common.getStat(path.join(root, 'package.json'), function (_, stats) {
|
|
@@ -83,13 +84,10 @@ function readPluginModules(dir, callback, plugins, isSys) {
|
|
|
83
84
|
obj.mtime = stats.mtime.getTime();
|
|
84
85
|
}
|
|
85
86
|
if (--len === 0) {
|
|
86
|
-
list.forEach(function (
|
|
87
|
-
var name = pluginUtil.getPluginName(
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
if (!old || (obj.mtime > old.mtime && obj.root === old.root)) {
|
|
91
|
-
plugins[name] = obj;
|
|
92
|
-
}
|
|
87
|
+
list.forEach(function (item) {
|
|
88
|
+
var name = pluginUtil.getPluginName(item.name);
|
|
89
|
+
if (item.root && pluginUtil.compparePlugin(dir, item.mtime, plugins[name])) {
|
|
90
|
+
plugins[name] = item;
|
|
93
91
|
}
|
|
94
92
|
});
|
|
95
93
|
callback(plugins);
|
|
@@ -121,10 +119,11 @@ module.exports = function (callback) {
|
|
|
121
119
|
if (pluginUtil.excludePlugin(name)) {
|
|
122
120
|
return;
|
|
123
121
|
}
|
|
124
|
-
var old = result[name + ':'];
|
|
125
122
|
var obj = plugins[name];
|
|
126
|
-
|
|
123
|
+
var dir = obj[PLUGIN_DIR];
|
|
124
|
+
if (pluginUtil.compparePlugin(dir, obj.mtime, result[name + ':'])) {
|
|
127
125
|
result[name + ':'] = {
|
|
126
|
+
[PLUGIN_DIR]: dir,
|
|
128
127
|
account: account,
|
|
129
128
|
dir: config.whistleName,
|
|
130
129
|
isSys: isSys,
|
|
@@ -1202,7 +1202,7 @@ module.exports = async function (options, callback) {
|
|
|
1202
1202
|
PROXY_ID_HEADER = config.PROXY_ID_HEADER;
|
|
1203
1203
|
options.getTempFilePath = function(filePath) {
|
|
1204
1204
|
if (common.TEMP_PATH_RE.test(filePath)) {
|
|
1205
|
-
return path.join(
|
|
1205
|
+
return path.join(common.TEMP_FILES_PATH, RegExp.$1);
|
|
1206
1206
|
}
|
|
1207
1207
|
};
|
|
1208
1208
|
|
|
@@ -36,6 +36,7 @@ var pluginPaths = config.pluginPaths;
|
|
|
36
36
|
if (pluginPaths) {
|
|
37
37
|
pluginPaths = pluginPaths.concat(pluginPaths.map(formatPath).concat(addon));
|
|
38
38
|
pluginPaths = prePlugins.concat(pluginPaths);
|
|
39
|
+
config.PLUGIN_INSTALL_ROOT = pluginPaths[0];
|
|
39
40
|
addDebugPaths(pluginPaths);
|
|
40
41
|
pluginPaths = uniqueArr(pluginPaths);
|
|
41
42
|
exports.getPaths = function () {
|
|
@@ -80,6 +81,9 @@ if (pluginsPath && paths.indexOf(pluginsPath) == -1) {
|
|
|
80
81
|
}
|
|
81
82
|
if (!config.customPluginPaths || !config.customPluginPaths.length) {
|
|
82
83
|
paths.unshift(config.CUSTOM_PLUGIN_PATH);
|
|
84
|
+
config.PLUGIN_INSTALL_ROOT = config.CUSTOM_PLUGIN_PATH;
|
|
85
|
+
} else {
|
|
86
|
+
config.PLUGIN_INSTALL_ROOT = config.customPluginPaths[0];
|
|
83
87
|
}
|
|
84
88
|
paths = addon.concat(paths);
|
|
85
89
|
addDebugPaths(paths);
|
package/lib/plugins/util.js
CHANGED
|
@@ -13,11 +13,14 @@ var MAX_EXPIRE = 36000;
|
|
|
13
13
|
var UTF8_OPTIONS = { encoding: 'utf8' };
|
|
14
14
|
var workerScript = util.readFileSync(path.join(__dirname, '../../assets/js/worker.js'), false);
|
|
15
15
|
var workers = {};
|
|
16
|
+
var PLUGIN_DIR = Symbol('dir');
|
|
16
17
|
|
|
17
18
|
function replaceScript(ctn, name) {
|
|
18
19
|
return workerScript.replace('$PLUGIN_NAME', name).replace('/*sourcecode*/', ctn);
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
exports.PLUGIN_DIR = PLUGIN_DIR;
|
|
23
|
+
|
|
21
24
|
exports.readWorkerSync = function(root, conf, name) {
|
|
22
25
|
var file = util.getWebWorker(conf);
|
|
23
26
|
file = file && util.readFileSync(path.join(root, file));
|
|
@@ -140,6 +143,7 @@ function setPlugin(plugins, pkg, root, mtime, sync) {
|
|
|
140
143
|
if (PLUGIN_NAME_RE.test(pkg.name)) {
|
|
141
144
|
var name = sync ? RegExp.$1 : getPluginName(RegExp.$1);
|
|
142
145
|
plugins[name] = {
|
|
146
|
+
[PLUGIN_DIR]: DEV_PLUGINS_PATH,
|
|
143
147
|
root: root,
|
|
144
148
|
mtime: mtime,
|
|
145
149
|
notUn: true,
|
|
@@ -256,3 +260,7 @@ exports.getSysPath = function(dir, name, isSys, cb) {
|
|
|
256
260
|
cb(exists ? sysRoot : root);
|
|
257
261
|
});
|
|
258
262
|
};
|
|
263
|
+
|
|
264
|
+
exports.compparePlugin = function (dir, mtime, old) {
|
|
265
|
+
return !old || (mtime > old.mtime && dir === old[PLUGIN_DIR]);
|
|
266
|
+
};
|