whistle 2.10.2 → 2.10.3
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/whistle.js +5 -5
- package/biz/webui/cgi-bin/download.js +1 -1
- package/biz/webui/cgi-bin/rules/clear-dns-cache.js +7 -0
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +53 -51
- package/biz/webui/lib/index.js +32 -2
- package/lib/config.js +3 -4
- package/lib/handlers/file-proxy.js +1 -1
- package/lib/https/ca.js +31 -0
- package/lib/https/index.js +3 -2
- package/lib/index.js +0 -2
- package/lib/inspectors/data.js +119 -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 +2 -3
- package/lib/service/composer.js +10 -5
- package/lib/service/service.js +14 -10
- package/lib/service/util.js +3 -42
- package/lib/socket-mgr.js +2 -16
- package/lib/util/common.js +44 -10
- package/lib/util/index.js +24 -4
- 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
|
@@ -148,7 +148,6 @@ function getDataDir(dirname) {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
config.baseDir = getDataDir();
|
|
151
|
-
config.TEMP_FILES_PATH = path.join(getWhistlePath(), 'temp_files');
|
|
152
151
|
config.CUSTOM_PLUGIN_PATH = path.join(getWhistlePath(), 'custom_plugins');
|
|
153
152
|
config.CUSTOM_CERTS_DIR = path.resolve(getWhistlePath(), 'custom_certs');
|
|
154
153
|
config.SAVED_SESSIONS_PATH = path.resolve(getWhistlePath(), 'saved_sessions');
|
|
@@ -158,8 +157,8 @@ config.valuesDir = path.join(config.baseDir, 'values');
|
|
|
158
157
|
config.propertiesDir = path.join(config.baseDir, 'properties');
|
|
159
158
|
|
|
160
159
|
try {
|
|
161
|
-
fse.ensureDirSync(
|
|
162
|
-
var blankFile = path.join(
|
|
160
|
+
fse.ensureDirSync(common.TEMP_FILES_PATH);
|
|
161
|
+
var blankFile = path.join(common.TEMP_FILES_PATH, 'blank');
|
|
163
162
|
if (!fs.existsSync(blankFile)) {
|
|
164
163
|
fs.writeFileSync(blankFile, '');
|
|
165
164
|
}
|
|
@@ -796,7 +795,7 @@ exports.extend = function (newConf) {
|
|
|
796
795
|
setDefaultResultOrder(m.toLowerCase());
|
|
797
796
|
} else if (m === 'proxyOnly') {
|
|
798
797
|
config.pureProxy = true;
|
|
799
|
-
} else if (m === 'useMultipleRules' || m === 'enableMultipleRules') {
|
|
798
|
+
} else if (m === 'useMultipleRules' || m === 'enableMultipleRules' || m === 'allowMultipleChoice') {
|
|
800
799
|
config.allowMultipleChoice = true;
|
|
801
800
|
} else if (m === 'disableMultipleRules') {
|
|
802
801
|
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
|
@@ -718,9 +718,10 @@ function resolveWebsocket(socket, wss) {
|
|
|
718
718
|
extend(headers, reqHeaders);
|
|
719
719
|
headers.host = headers.host || host;
|
|
720
720
|
}
|
|
721
|
-
|
|
721
|
+
authObj = auth || authObj;
|
|
722
|
+
auth = util.getAuthBasic(authObj);
|
|
722
723
|
if (auth) {
|
|
723
|
-
headers['authorization'] = auth;
|
|
724
|
+
headers[(authObj.proxy ? 'proxy-' : '') + 'authorization'] = auth;
|
|
724
725
|
}
|
|
725
726
|
var reqRuleData = { headers: headers };
|
|
726
727
|
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;
|
|
@@ -167,12 +243,20 @@ function emitDataEvents(req, res, proxy) {
|
|
|
167
243
|
var captureReqStream;
|
|
168
244
|
var maxReqSize;
|
|
169
245
|
var reqInfo;
|
|
246
|
+
var setReqBody = function (body, end) {
|
|
247
|
+
if (captureReqStream && cseSep) {
|
|
248
|
+
reqBody = parseFrame(reqBody, false, end);
|
|
249
|
+
} else {
|
|
250
|
+
reqData.body = reqBody;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
170
253
|
var updateReqInfo = function() {
|
|
171
254
|
if (reqInfo && !captureReqStream) {
|
|
172
255
|
captureReqStream = !disable.captureStream && (resDone || enable.captureStream) && !getZipType(reqInfo);
|
|
173
256
|
maxReqSize = useBigData ? BIG_DATA_SIZE : (captureReqStream ? MAX_REQ_BODY_SIZE : MAX_SIZE);
|
|
174
|
-
if (captureReqStream
|
|
175
|
-
|
|
257
|
+
if (captureReqStream) {
|
|
258
|
+
data.isCse = !!cseSep;
|
|
259
|
+
reqBody && !reqData.body && setReqBody(reqBody);
|
|
176
260
|
}
|
|
177
261
|
}
|
|
178
262
|
};
|
|
@@ -198,7 +282,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
198
282
|
} else {
|
|
199
283
|
reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
|
|
200
284
|
if (captureReqStream) {
|
|
201
|
-
|
|
285
|
+
setReqBody(reqBody);
|
|
202
286
|
}
|
|
203
287
|
if (reqBody.length > maxReqSize) {
|
|
204
288
|
reqBody = false;
|
|
@@ -225,8 +309,8 @@ function emitDataEvents(req, res, proxy) {
|
|
|
225
309
|
data.endTime = endTime;
|
|
226
310
|
}
|
|
227
311
|
reqBody = err ? util.getErrorStack(err) : body;
|
|
228
|
-
|
|
229
|
-
setUnzipSize(body, reqData);
|
|
312
|
+
setReqBody(reqBody, true);
|
|
313
|
+
!data.isCse && setUnzipSize(body, reqData);
|
|
230
314
|
checkBodySize(reqData, useBigData);
|
|
231
315
|
});
|
|
232
316
|
updateEvent && proxy.emit(updateEvent, req.fullUrl, false, true);
|
|
@@ -239,9 +323,22 @@ function emitDataEvents(req, res, proxy) {
|
|
|
239
323
|
}
|
|
240
324
|
resDone = true;
|
|
241
325
|
info = info || (res._needGunzip ? { statusCode: res.statusCode, headers: '' } : res);
|
|
242
|
-
var
|
|
243
|
-
|
|
326
|
+
var isSse;
|
|
327
|
+
var captureStream;
|
|
328
|
+
if (!disable.captureStream && !getZipType(info)) {
|
|
329
|
+
var headers = info.headers;
|
|
330
|
+
captureStream = requestTime == null || enable.captureStream;
|
|
331
|
+
if (headers) {
|
|
332
|
+
isSse = headers['content-type'] === 'text/event-stream';
|
|
333
|
+
captureStream = captureStream || isSse;
|
|
334
|
+
resSepInfo = parseFrameSep(headers);
|
|
335
|
+
if (resSepInfo && resSepInfo.sep) {
|
|
336
|
+
isSse = captureStream;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
244
340
|
var maxResSize = useBigData ? BIG_DATA_SIZE : (captureStream ? MAX_RES_BODY_SIZE : MAX_SIZE);
|
|
341
|
+
data.isSse = isSse;
|
|
245
342
|
captureStream && updateReqInfo();
|
|
246
343
|
if (!cleared && util.hasBody(info, req) && checkType(info)) {
|
|
247
344
|
if (info.headers['content-length'] > maxResSize && !captureStream) {
|
|
@@ -261,9 +358,13 @@ function emitDataEvents(req, res, proxy) {
|
|
|
261
358
|
} else {
|
|
262
359
|
resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
|
|
263
360
|
if (captureStream) {
|
|
264
|
-
|
|
361
|
+
if (isSse) {
|
|
362
|
+
resBody = parseFrame(resBody, true);
|
|
363
|
+
} else {
|
|
364
|
+
resData.body = resBody;
|
|
365
|
+
}
|
|
265
366
|
}
|
|
266
|
-
if (resBody.length > maxResSize) {
|
|
367
|
+
if (resBody && resBody.length > maxResSize) {
|
|
267
368
|
resBody = false;
|
|
268
369
|
}
|
|
269
370
|
}
|
|
@@ -286,9 +387,13 @@ function emitDataEvents(req, res, proxy) {
|
|
|
286
387
|
resData.hasGzipError = unzipBody(info, resBody, function (err, body) {
|
|
287
388
|
if (!data.resError) {
|
|
288
389
|
resBody = err ? util.getErrorStack(err) : body;
|
|
289
|
-
|
|
390
|
+
if (isSse) {
|
|
391
|
+
resBody = parseFrame(resBody, true, true);
|
|
392
|
+
} else {
|
|
393
|
+
resData.body = resBody;
|
|
394
|
+
}
|
|
290
395
|
}
|
|
291
|
-
setUnzipSize(body, resData);
|
|
396
|
+
!isSse && setUnzipSize(body, resData);
|
|
292
397
|
checkBodySize(resData, useBigData);
|
|
293
398
|
setEndTime();
|
|
294
399
|
reqEmitter.emit('end', data);
|
|
@@ -341,7 +446,8 @@ function emitDataEvents(req, res, proxy) {
|
|
|
341
446
|
}
|
|
342
447
|
!endTime && setEndTime();
|
|
343
448
|
delete data.abort;
|
|
344
|
-
|
|
449
|
+
var msg = err && err.message;
|
|
450
|
+
if (msg !== 'Aborted') {
|
|
345
451
|
data.resError = true;
|
|
346
452
|
if (resData.body) {
|
|
347
453
|
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
|
+
};
|
package/lib/rules/dns.js
CHANGED
package/lib/rules/rules.js
CHANGED
|
@@ -14,7 +14,6 @@ var env = process.env || {};
|
|
|
14
14
|
var allowDnsCache = true;
|
|
15
15
|
var SUB_MATCH_RE = /\$[&\d]/;
|
|
16
16
|
var BODY_MATCH_RE = /\$b[&\d]/;
|
|
17
|
-
var SPACE_RE = /\s+/g;
|
|
18
17
|
var EXACT_RE = /^\$/;
|
|
19
18
|
var NON_RE = /^!/;
|
|
20
19
|
var HAS_SPACE_RE = /\s/;
|
|
@@ -371,7 +370,7 @@ function joinUrl(a, b) {
|
|
|
371
370
|
}
|
|
372
371
|
|
|
373
372
|
function toLine(_, line) {
|
|
374
|
-
return line.replace(
|
|
373
|
+
return line.replace(/\s+/g, ' ');
|
|
375
374
|
}
|
|
376
375
|
|
|
377
376
|
function mergeLines(text) {
|
|
@@ -1866,7 +1865,7 @@ function matchFilter(url, filter, req) {
|
|
|
1866
1865
|
if (keyLen > 0 && key[keyLen] === '%') {
|
|
1867
1866
|
key = key.substring(0, keyLen) / 100;
|
|
1868
1867
|
}
|
|
1869
|
-
return getFilterResult(Math.random() <
|
|
1868
|
+
return getFilterResult(Math.random() < key, filter);
|
|
1870
1869
|
}
|
|
1871
1870
|
if (filterProp(req.method, filter.method, filter.mPattern)) {
|
|
1872
1871
|
return getFilterResult(result, filter);
|
package/lib/service/composer.js
CHANGED
|
@@ -38,7 +38,12 @@ function saveComposerHistory() {
|
|
|
38
38
|
} catch (e) {}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
41
|
+
function getUrl(url, isConn) {
|
|
42
|
+
url = isConn ? url.replace(/[?#].*$/, '') : url;
|
|
43
|
+
return url.length > MAX_URL_LEN ? url.substring(0, MAX_URL_LEN) : url;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function handleComposerHistory(data, isConn) {
|
|
42
47
|
var url = data.url;
|
|
43
48
|
var method = data.method;
|
|
44
49
|
var headers = data.headers;
|
|
@@ -50,7 +55,7 @@ function handleComposerHistory(data) {
|
|
|
50
55
|
var result = {
|
|
51
56
|
date: Date.now(),
|
|
52
57
|
useH2: data.useH2,
|
|
53
|
-
url: url
|
|
58
|
+
url: getUrl(url, isConn),
|
|
54
59
|
method:
|
|
55
60
|
method.length > MAX_METHOD_LEN
|
|
56
61
|
? method.substring(0, MAX_METHOD_LEN)
|
|
@@ -335,13 +340,13 @@ function getCharset(headers) {
|
|
|
335
340
|
exports.handleRequest = function(req, res) {
|
|
336
341
|
var fullUrl = req.body.url;
|
|
337
342
|
if (!fullUrl || typeof fullUrl !== 'string') {
|
|
338
|
-
return res.json({ec:
|
|
343
|
+
return res.json({ec: 2, em: 'Invalid URL'});
|
|
339
344
|
}
|
|
340
345
|
|
|
341
346
|
fullUrl = common.encodeNonLatin1Char(fullUrl.replace(/#.*$/, ''));
|
|
342
347
|
var options = common.parseUrl(common.setProtocol(fullUrl));
|
|
343
348
|
if (!options.host) {
|
|
344
|
-
return res.json({ec:
|
|
349
|
+
return res.json({ec: 2, em: 'Invalid URL'});
|
|
345
350
|
}
|
|
346
351
|
var protocol = options.protocol;
|
|
347
352
|
if (protocol) {
|
|
@@ -386,7 +391,7 @@ exports.handleRequest = function(req, res) {
|
|
|
386
391
|
}
|
|
387
392
|
}
|
|
388
393
|
if (!req.body.noStore && req.body.needResponse && common.checkHistory(req.body)) {
|
|
389
|
-
handleComposerHistory(req.body);
|
|
394
|
+
handleComposerHistory(req.body, isConn);
|
|
390
395
|
dataCenter.saveData({
|
|
391
396
|
type: 'composer',
|
|
392
397
|
history: composerHistory
|