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.
@@ -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.isTempFile(query.filename);
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
- proxyEvent.loadService(function(err, options) {
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(config.TEMP_FILES_PATH);
162
- var blankFile = path.join(config.TEMP_FILES_PATH, 'blank');
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+/g);
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());
@@ -718,9 +718,10 @@ function resolveWebsocket(socket, wss) {
718
718
  extend(headers, reqHeaders);
719
719
  headers.host = headers.host || host;
720
720
  }
721
- auth = util.getAuthBasic(auth || authObj);
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;
@@ -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 SSE_RE = /^\s*text\/event-stream/i;
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 && reqBody && !reqData.body) {
175
- reqData.body = reqBody;
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
- reqData.body = reqBody;
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
- reqData.body = reqBody;
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 captureStream = !disable.captureStream && (requestTime == null || enable.captureStream ||
243
- (info.headers && SSE_RE.test(info.headers['content-type']))) && !getZipType(info);
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
- resData.body = resBody;
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
- resData.body = resBody;
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
- if (err && err.message !== 'Aborted') {
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);
@@ -147,9 +147,11 @@ function handleReq(req, data, reqRules, delType) {
147
147
  }
148
148
  }
149
149
 
150
- function handleAuth(data, auth) {
151
- auth = util.getAuthBasic(auth);
152
- auth && util.setHeader(data, 'authorization', auth);
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 (!old || (mtime > old.mtime && root === old.root)) {
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 (!old || (mtime > old.mtime && root === old.root)) {
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 dir = plugins[name];
99
- var account = dir.account;
100
- var isSys = dir.isSys;
101
- var isProj = dir.isProj;
102
- var notUn = dir.notUn;
103
- var isDev = dir.isDev;
104
- var dirName = dir.dir;
105
- var mtime = dir.mtime;
106
- dir = dir.root;
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
- dir: dir
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
- dir: dir
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.dir;
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 (obj) {
87
- var name = pluginUtil.getPluginName(obj.name);
88
- if (obj.root) {
89
- var old = plugins[name];
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
- if (!old || (obj.mtime > old.mtime && obj.root === old.path)) {
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(config.TEMP_FILES_PATH, RegExp.$1);
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);
@@ -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
@@ -177,3 +177,7 @@ module.exports = function lookup(hostname, callback, allowDnsCache) {
177
177
  err ? lookupDNS(hostname, callback) : callback(err, ip);
178
178
  });
179
179
  };
180
+
181
+ module.exports.clearCache = function() {
182
+ dnsCache = {};
183
+ };
@@ -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(SPACE_RE, ' ');
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() < chance.key, filter);
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);
@@ -38,7 +38,12 @@ function saveComposerHistory() {
38
38
  } catch (e) {}
39
39
  }
40
40
 
41
- function handleComposerHistory(data) {
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.length > MAX_URL_LEN ? url.substring(0, MAX_URL_LEN) : 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: 0});
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: 0});
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