whistle 2.10.1 → 2.10.2

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.
@@ -56,7 +56,24 @@ var INSPECTOR_URL = '???_WHISTLE_PLUGIN_INSPECTOR_TAB_' + config.port + '???';
56
56
  var KEY_RE_G = /\${[^{}\s]+}|{\S+}/g;
57
57
  var COMMENT_RE = /#[^\r\n]*$/mg;
58
58
 
59
+ function hasLogin() {
60
+ return config.username && config.password;
61
+ }
62
+
63
+ function isTempFile(query) {
64
+ var files = query.files;
65
+ if (files && typeof files === 'string') {
66
+ return false;
67
+ }
68
+ return common.isTempFile(query.filename);
69
+ }
70
+
59
71
  function sendToService(req, res) {
72
+ if (!hasLogin() && req.path === '/cgi-bin/temp/get' && !isTempFile(req.query)) {
73
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
74
+ res.end('{"ec":0,"value":"","forbidden":true}');
75
+ return;
76
+ }
60
77
  proxyEvent.loadService(function(err, options) {
61
78
  if (err) {
62
79
  common.sendRes(res, 500, err.stack || err);
@@ -393,10 +410,8 @@ function cgiHandler(req, res) {
393
410
  app.all('/service/*', sendToService);
394
411
  app.all('/cgi-bin/service/*', sendToService);
395
412
  app.all('/cgi-bin/sessions/*', sendToService);
413
+ app.all('/cgi-bin/log/*', sendToService);
396
414
  app.post('/cgi-bin/plugins/install', sendToService);
397
- app.all('/favicon.ico', function(req, res) {
398
- res.sendFile(htdocs.getImgFile('favicon.ico'));
399
- });
400
415
 
401
416
  function readPluginPage(req, res, plugin, html, config) {
402
417
  res.type('html');
package/lib/config.js CHANGED
@@ -153,6 +153,9 @@ 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');
155
155
  config.DEV_PLUGINS_PATH = path.resolve(getWhistlePath(), 'dev_plugins');
156
+ config.rulesDir = path.join(config.baseDir, 'rules');
157
+ config.valuesDir = path.join(config.baseDir, 'values');
158
+ config.propertiesDir = path.join(config.baseDir, 'properties');
156
159
 
157
160
  try {
158
161
  fse.ensureDirSync(config.TEMP_FILES_PATH);
package/lib/https/ca.js CHANGED
@@ -15,8 +15,6 @@ var common = require('../util/common');
15
15
  var rulesUtil = require('../rules/util');
16
16
 
17
17
  var pki = forge.pki;
18
- var CUR_VERSION = process.version;
19
- var requiredVersion = parseInt(CUR_VERSION.slice(1), 10) >= 6;
20
18
  var HTTPS_DIR = mkdir(path.join(config.getDataDir(), 'certs'));
21
19
  var ROOT_NEW_KEY_FILE = path.join(HTTPS_DIR, 'root_new.key');
22
20
  var ROOT_NEW_CRT_FILE = path.join(HTTPS_DIR, 'root_new.crt');
@@ -40,6 +38,7 @@ var customCertCount = 0;
40
38
  var cachePairs = new LRU({ max: 5120 });
41
39
  var certsCache = new LRU({ max: 256 });
42
40
  var remoteCerts = new LRU({ max: 1280 });
41
+ var KEY_SIZE = 2048;
43
42
  var ILEGAL_CHAR_RE = /[^a-z\d-]/i;
44
43
  // https://cloud.tencent.com/developer/ask/sof/58155
45
44
  var RANDOM_SERIAL = '/' + Date.now() + '/' + process.pid + '/' + Math.floor(Math.random() * 100);
@@ -58,12 +57,12 @@ exports.remoteCerts = remoteCerts;
58
57
  exports.createSecureContext = createSecureContext;
59
58
  exports.CUSTOM_CERTS_DIR = CUSTOM_CERTS_DIR;
60
59
 
61
- function isRootCa(name) {
60
+ function notRootCa(name) {
62
61
  return name !== 'root';
63
62
  }
64
63
 
65
64
  function checkFilename(name) {
66
- return name && !ILLEGAL_PATH_RE.test(name) && isRootCa(name);
65
+ return name && !ILLEGAL_PATH_RE.test(name) && notRootCa(name);
67
66
  }
68
67
 
69
68
  function resetAllCerts() {
@@ -84,7 +83,7 @@ if (timer && typeof timer.unref === 'function') {
84
83
  timer.unref();
85
84
  }
86
85
 
87
- if (!useNewKey && requiredVersion && !checkCertificate()) {
86
+ if (!useNewKey && !checkCertificate()) {
88
87
  try {
89
88
  fs.unlinkSync(ROOT_KEY_FILE);
90
89
  fs.unlinkSync(ROOT_CRT_FILE);
@@ -108,7 +107,7 @@ function isExpiredCert(crt) {
108
107
  function checkCertificate() {
109
108
  try {
110
109
  var crt = pki.certificateFromPem(fs.readFileSync(ROOT_CRT_FILE));
111
- if (crt.publicKey.n.toString(2).length < 2048 || isExpiredCert(crt.validity)) {
110
+ if (crt.publicKey.n.toString(2).length < KEY_SIZE || isExpiredCert(crt.validity)) {
112
111
  return false;
113
112
  }
114
113
  return /^whistle\.\d+$/.test(getCommonName(crt));
@@ -265,7 +264,7 @@ function parseAllCustomCerts() {
265
264
  var validity = info.validity;
266
265
  var altNames = info.altNames;
267
266
  var dnsName = [];
268
- var disabled = (isRootCa(filename) && rulesUtil.isDisabledCertFile(filename)) || undefined;
267
+ var disabled = (notRootCa(filename) && rulesUtil.isDisabledCertFile(filename)) || undefined;
269
268
  altNames.forEach(function (item) {
270
269
  if ((item.type === 2 || item.type === 7) && !pairs[item.value]) {
271
270
  if (!disabled) {
@@ -439,7 +438,7 @@ function createRootCA() {
439
438
 
440
439
  function createCACert(opts) {
441
440
  opts = opts || {};
442
- var keys = pki.rsa.generateKeyPair(requiredVersion ? 2048 : 1024);
441
+ var keys = pki.rsa.generateKeyPair(KEY_SIZE);
443
442
  var cert = createCert(keys.publicKey);
444
443
  var now = Date.now() + common.padLeft(Math.floor(Math.random() * 1000), 3);
445
444
  var attrs = [
@@ -757,7 +756,7 @@ exports.setActiveCert = function (opts) {
757
756
  return;
758
757
  }
759
758
  var filename = opts.filename;
760
- if (isRootCa(filename) && allCustomCerts[filename]) {
759
+ if (notRootCa(filename) && allCustomCerts[filename]) {
761
760
  rulesUtil.setDisabledCertFile(filename, opts.disabled);
762
761
  parseAllCustomCerts();
763
762
  }
@@ -207,7 +207,7 @@ function resolveWebsocket(socket, wss) {
207
207
  };
208
208
 
209
209
  var plugin = pluginMgr.resolveWhistlePlugins(socket);
210
- abortIfUnavailable(socket);
210
+ handleEnd(socket);
211
211
  pluginMgr.getRules(socket, function (rulesMgr) {
212
212
  if (rulesMgr) {
213
213
  socket.pluginRules = rulesMgr;
@@ -394,7 +394,7 @@ function resolveWebsocket(socket, wss) {
394
394
  proxySocket.on('error', handleProxyError);
395
395
  reqSocket = proxySocket;
396
396
  proxySocket.on('secureConnect', function () {
397
- abortIfUnavailable(reqSocket);
397
+ handleEnd(reqSocket);
398
398
  pipeData();
399
399
  });
400
400
  } catch (e) {
@@ -403,7 +403,7 @@ function resolveWebsocket(socket, wss) {
403
403
  return;
404
404
  }
405
405
  reqSocket = proxySocket;
406
- abortIfUnavailable(reqSocket);
406
+ handleEnd(reqSocket);
407
407
  pipeData();
408
408
  };
409
409
  // 对应 internal-proxy 要用直接请求,方便用来穿透 nginx
@@ -557,7 +557,7 @@ function resolveWebsocket(socket, wss) {
557
557
  return execCallback(e);
558
558
  }
559
559
  if (retryConnect) {
560
- abortIfUnavailable(reqSocket);
560
+ handleEnd(reqSocket);
561
561
  } else {
562
562
  retryConnect = function (e) {
563
563
  if (!newIp && (newIp = util.getLocalhostIP(e, socket, socket._w2hostname, socket.hostIp))) {
@@ -621,7 +621,7 @@ function resolveWebsocket(socket, wss) {
621
621
  var disable = socket.disable;
622
622
  if (retryConnect) {
623
623
  reqSocket.removeListener('error', retryConnect);
624
- abortIfUnavailable(reqSocket);
624
+ handleEnd(reqSocket);
625
625
  retryConnect = null;
626
626
  }
627
627
  clearTimeout(timeout);
@@ -847,7 +847,7 @@ function resolveWebsocket(socket, wss) {
847
847
  }
848
848
  }
849
849
 
850
- function abortIfUnavailable(socket) {
850
+ function handleEnd(socket) {
851
851
  return util.onSocketEnd(socket, destroy);
852
852
  }
853
853
  var destroyed, reqDestroyed, resDestroyed;
@@ -1080,11 +1080,10 @@ function toHttp1(req, res) {
1080
1080
  formatRawHeaders(svrRes, isH2)
1081
1081
  );
1082
1082
  var write = res.write;
1083
- var handleError = function (e) {
1084
- e && handleAbort();
1085
- };
1086
1083
  res.write = function (chunk) {
1087
- return write.call(res, chunk, handleError);
1084
+ return write.call(res, chunk, function (e) {
1085
+ e && handleAbort();
1086
+ });
1088
1087
  };
1089
1088
  svrRes.pipe(res);
1090
1089
  res.flushHeaders && res.flushHeaders();
@@ -1168,152 +1167,147 @@ module.exports = function (socket, next, isWebPort) {
1168
1167
 
1169
1168
  util.onSocketEnd(socket, destroy);
1170
1169
 
1171
- function abortIfUnavailable(s) {
1172
- return s.on('error', destroy);
1173
- }
1174
1170
  var clientIp = socket.clientIp;
1175
1171
  var clientPort = socket.clientPort;
1176
- util.readOneChunk(
1177
- socket,
1178
- function (chunk) {
1179
- headersStr = chunk && chunk.toString();
1180
- var isHttp = chunk && HTTP_RE.test(headersStr);
1181
- var statusLine = isHttp && RegExp['$&'];
1182
- if (isHttp && CONNECT_RE.test(RegExp.$1)) {
1183
- chunk = addClientInfo(socket, chunk, statusLine, clientIp, clientPort);
1184
- util.connect(
1185
- {
1186
- port: config.port,
1187
- host: LOCALHOST
1188
- },
1172
+ util.readOneChunk(socket, function (chunk) {
1173
+ headersStr = chunk && chunk.toString();
1174
+ var isHttp = chunk && HTTP_RE.test(headersStr);
1175
+ var statusLine = isHttp && RegExp['$&'];
1176
+ if (isHttp && CONNECT_RE.test(RegExp.$1)) {
1177
+ chunk = addClientInfo(socket, chunk, statusLine, clientIp, clientPort);
1178
+ util.connect(
1179
+ {
1180
+ port: config.port,
1181
+ host: config.host || LOCALHOST
1182
+ },
1189
1183
  function (err, s) {
1190
1184
  reqSocket = s;
1191
1185
  if (err || socket._hasError) {
1192
1186
  return destroy(err);
1193
1187
  }
1188
+ reqSocket.on('error', destroy);
1194
1189
  reqSocket.write(chunk);
1195
1190
  reqSocket.pipe(socket).pipe(reqSocket);
1196
- abortIfUnavailable(reqSocket);
1197
1191
  socket.resume();
1198
1192
  }
1199
1193
  );
1200
- return;
1201
- }
1202
- if (!chunk) {
1194
+ return;
1195
+ }
1196
+ if (!chunk) {
1203
1197
  //没有数据
1204
- return isWebPort ? socket.destroy() : next(chunk);
1205
- }
1206
- if (isHttp) {
1207
- if (isEnable('forHttps') || disable.captureHttp) {
1208
- next(chunk);
1209
- } else {
1210
- socket.resume();
1211
- server.emit('connection', socket);
1212
- socket.emit(
1198
+ return isWebPort ? socket.destroy() : next(chunk);
1199
+ }
1200
+ if (isHttp) {
1201
+ if (isEnable('forHttps') || disable.captureHttp) {
1202
+ next(chunk);
1203
+ } else {
1204
+ socket.resume();
1205
+ server.emit('connection', socket);
1206
+ socket.emit(
1213
1207
  'data',
1214
1208
  addClientInfo(socket, chunk, statusLine, clientIp, clientPort)
1215
1209
  );
1216
- }
1217
- } else if (isEnable('forHttp') || disable.captureHttps) {
1210
+ }
1211
+ } else if (isEnable('forHttp') || disable.captureHttps) {
1212
+ return next(chunk);
1213
+ } else {
1214
+ var isHttpH2 = HTTP2_RE.test(headersStr);
1215
+ if (!isHttpH2 && chunk[0] != 22) {
1218
1216
  return next(chunk);
1219
- } else {
1220
- var isHttpH2 = HTTP2_RE.test(headersStr);
1221
- if (!isHttpH2 && chunk[0] != 22) {
1222
- return next(chunk);
1223
- }
1224
- var useSNI, domain, serverKey;
1225
- var handleConnect = function (port) {
1226
- var promise =
1217
+ }
1218
+ var useSNI, domain, serverKey;
1219
+ var handleConnect = function (port) {
1220
+ var promise =
1227
1221
  !isHttpH2 && !useSNI && serverAgent.existsServer(serverKey);
1228
- var httpsServer = promise && promise.cert && promise.server;
1229
- if (httpsServer && httpsServer.setSecureContext) {
1230
- var cert = serverAgent.createCertificate(domain);
1231
- if (
1222
+ var httpsServer = promise && promise.cert && promise.server;
1223
+ if (httpsServer && httpsServer.setSecureContext) {
1224
+ var cert = serverAgent.createCertificate(domain);
1225
+ if (
1232
1226
  cert.key !== promise.cert.key ||
1233
1227
  cert.cert !== promise.cert.cert
1234
1228
  ) {
1235
- try {
1236
- cert._ctx = cert._ctx || ca.createSecureContext(cert);
1237
- httpsServer.setSecureContext(cert._ctx);
1238
- promise.cert = cert;
1239
- } catch (e) {}
1240
- }
1229
+ try {
1230
+ cert._ctx = cert._ctx || ca.createSecureContext(cert);
1231
+ httpsServer.setSecureContext(cert._ctx);
1232
+ promise.cert = cert;
1233
+ } catch (e) {}
1241
1234
  }
1242
- util.connect(
1243
- {
1244
- port: port,
1245
- host: LOCALHOST,
1246
- localAddress: LOCALHOST
1247
- },
1235
+ }
1236
+ util.connect(
1237
+ {
1238
+ port: port,
1239
+ host: LOCALHOST,
1240
+ localAddress: LOCALHOST
1241
+ },
1248
1242
  function (err, s) {
1249
1243
  reqSocket = s;
1250
1244
  if (err || socket._hasError) {
1251
1245
  return destroy(err);
1252
1246
  }
1247
+ reqSocket.on('error', destroy);
1253
1248
  socket._w2TunnelKey = reqSocket.localPort + ':' + reqSocket.remotePort;
1254
1249
  tunnelTmplData.set(socket._w2TunnelKey, getTunnelData(socket, clientIp, clientPort, isHttpH2));
1255
1250
  reqSocket.write(chunk);
1256
1251
  reqSocket.pipe(socket).pipe(reqSocket);
1257
1252
  socket.resume();
1258
- abortIfUnavailable(reqSocket);
1259
1253
  }
1260
1254
  );
1261
- };
1262
- var useNoSNIServer = function () {
1263
- serverKey = requestCert ? ':' + domain : domain;
1264
- serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
1265
- };
1255
+ };
1256
+ var useNoSNIServer = function () {
1257
+ serverKey = requestCert ? ':' + domain : domain;
1258
+ serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
1259
+ };
1266
1260
 
1267
- var handleRequest = function () {
1268
- if (useSNI) {
1269
- var disableH2 = !properties.isEnableHttp2();
1270
- if (disable.http2) {
1271
- disableH2 = true;
1272
- } else if (enable.http2) {
1273
- disableH2 = false;
1274
- }
1275
- getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
1276
- } else if (isHttpH2) {
1277
- getHttp2Server(h2Handlers, handleConnect);
1278
- } else {
1279
- useNoSNIServer();
1261
+ var handleRequest = function () {
1262
+ if (useSNI) {
1263
+ var disableH2 = !properties.isEnableHttp2();
1264
+ if (disable.http2) {
1265
+ disableH2 = true;
1266
+ } else if (enable.http2) {
1267
+ disableH2 = false;
1280
1268
  }
1281
- };
1282
- if (isHttpH2) {
1283
- return handleRequest();
1269
+ getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
1270
+ } else if (isHttpH2) {
1271
+ getHttp2Server(h2Handlers, handleConnect);
1272
+ } else {
1273
+ useNoSNIServer();
1284
1274
  }
1285
- useSNI = checkSNI(chunk);
1286
- var servername = useSNI || socket.tunnelHostname;
1287
- if (
1275
+ };
1276
+ if (isHttpH2) {
1277
+ return handleRequest();
1278
+ }
1279
+ useSNI = checkSNI(chunk);
1280
+ var servername = useSNI || socket.tunnelHostname;
1281
+ if (
1288
1282
  !servername ||
1289
1283
  (useSNI ? disable.captureSNI : (disable.captureNoSNI || (net.isIP(servername) && !isCaptureIp()))) ||
1290
1284
  (socket.useProxifier && !ca.existsCustomCert(servername))
1291
1285
  ) {
1292
- return next(chunk);
1293
- }
1294
- var requestCert =
1286
+ return next(chunk);
1287
+ }
1288
+ var requestCert =
1295
1289
  (enable.clientCert || enable.requestCert) &&
1296
1290
  !disable.clientCert &&
1297
1291
  !disable.requestCert;
1298
- domain = getDomain(servername);
1299
- socket.curUrl = socket.fullUrl = 'https://' + servername;
1300
- socket.useSNI = useSNI;
1301
- socket.serverName = socket.servername = servername;
1302
- socket.commonName = domain;
1303
- loadCert(socket, function (cert) {
1304
- if (socket._hasError) {
1305
- return destroy();
1306
- }
1307
- if (cert === false) {
1308
- return next(chunk);
1309
- }
1310
- if (cert) {
1311
- domain = servername;
1312
- }
1313
- handleRequest();
1314
- });
1315
- }
1316
- },
1292
+ domain = getDomain(servername);
1293
+ socket.curUrl = socket.fullUrl = 'https://' + servername;
1294
+ socket.useSNI = useSNI;
1295
+ socket.serverName = socket.servername = servername;
1296
+ socket.commonName = domain;
1297
+ loadCert(socket, function (cert) {
1298
+ if (socket._hasError) {
1299
+ return destroy();
1300
+ }
1301
+ if (cert === false) {
1302
+ return next(chunk);
1303
+ }
1304
+ if (cert) {
1305
+ domain = servername;
1306
+ }
1307
+ handleRequest();
1308
+ });
1309
+ }
1310
+ },
1317
1311
  isWebPort ? 0 : TIMEOUT
1318
1312
  );
1319
1313
  };
package/lib/index.js CHANGED
@@ -11,7 +11,6 @@ var setupHttps = require('./https').setup;
11
11
  var httpsUtil = require('./https/ca');
12
12
  var rulesUtil = require('./rules/util');
13
13
  var initDataServer = require('./util/data-server');
14
- var initLogServer = require('./util/log-server');
15
14
  var pluginMgr = require('./plugins');
16
15
  var config = require('./config');
17
16
  var loadService = require('./service');
@@ -61,7 +60,6 @@ function proxy(callback, _server) {
61
60
  tunnelProxy(server, proxyEvents);
62
61
  upgradeProxy(server);
63
62
  initDataServer(proxyEvents);
64
- initLogServer(proxyEvents);
65
63
  rulesUtil.setup(proxyEvents);
66
64
  var properties = rulesUtil.properties;
67
65
  if (config.disableAllRules) {
@@ -254,7 +252,7 @@ function handleGlobalException(err) {
254
252
  code === 'ERR_HTTP_TRAILER_INVALID' ||
255
253
  code === 'ERR_INTERNAL_ASSERTION' ||
256
254
  code === 'ERR_INVALID_ARG_TYPE' ||
257
- (err && /finishwrite/i.test(err.message)))
255
+ (err && /finishwrite|'_hadError'/i.test(err.message)))
258
256
  ) {
259
257
  return;
260
258
  }
@@ -29,7 +29,11 @@ module.exports = function (req, res) {
29
29
  if (log) {
30
30
  util.disableReqCache(req.headers);
31
31
  var host = req.headers.host;
32
+ delete req.rules.log;
32
33
  res.on('src', function (_res) {
34
+ if (!(log = req.rules.log) || !util.hasBody(_res)) {
35
+ return;
36
+ }
33
37
  var topScript, isHtml;
34
38
  if (util.supportHtmlTransform(_res, req)) {
35
39
  isHtml = true;
@@ -21,17 +21,22 @@ function getScript(host, name, isHtml, req) {
21
21
  }
22
22
 
23
23
  module.exports = function (req, res) {
24
- if (req.rules.weinre) {
24
+ var weinre = req.rules.weinre;
25
+ if (weinre) {
25
26
  util.disableReqCache(req.headers);
27
+ delete req.rules.weinre;
26
28
  var host = req.headers.host;
27
29
  res.on('src', function (_res) {
30
+ if (!(weinre = req.rules.weinre) || !util.hasBody(_res)) {
31
+ return;
32
+ }
28
33
  var isHtml = util.supportHtmlTransform(_res, req);
29
34
  if (!isHtml && util.getContentType(_res.headers) !== 'JS') {
30
35
  return;
31
36
  }
32
37
  !util.isEnable(req, 'keepAllCSP') && util.disableCSP(_res.headers);
33
38
  !req._customCache && util.disableResStore(_res.headers);
34
- var name = util.getPath(util.rule.getMatcher(req.rules.weinre));
39
+ var name = util.getPath(util.rule.getMatcher(weinre));
35
40
  var transform = new Transform();
36
41
  transform._transform = function (chunk, _, callback) {
37
42
  if (!chunk) {
@@ -63,7 +63,6 @@ exports.hasReqScript = rules.hasReqScript.bind(rules);
63
63
  exports.resolveDisable = rules.resolveDisable.bind(rules);
64
64
  exports.resolvePipe = rules.resolvePipe.bind(rules);
65
65
  exports.resolveRule = rules.resolveRule.bind(rules);
66
- exports.resolveRules = resolveReqRules;
67
66
  exports.resolveResRules = rules.resolveResRules.bind(rules);
68
67
  exports.resolveBodyFilter = rules.resolveBodyFilter.bind(rules);
69
68
  exports.lookupHost = rules.lookupHost.bind(rules);
@@ -73,6 +73,7 @@ var protocols = [
73
73
  'cipher',
74
74
  'sniCallback'
75
75
  ];
76
+ var toolProtocols = ['log', 'weinre'];
76
77
 
77
78
  var RULE_RE = /^(?:|x|xs)(?:file|rawfile|dust|tpl|jsonp):/;
78
79
  var LOC_RE = /^locationHref:/;
@@ -86,7 +87,6 @@ var pureResProtocols = [
86
87
  'resDelay',
87
88
  'resSpeed',
88
89
  'resType',
89
- 'resType',
90
90
  'resCharset',
91
91
  'resCookies',
92
92
  'resCors',
@@ -108,7 +108,7 @@ var pureResProtocols = [
108
108
  'htmlPrepend',
109
109
  'jsPrepend',
110
110
  'responseFor'
111
- ];
111
+ ].concat(toolProtocols);
112
112
  var resProtocols = [
113
113
  'filter',
114
114
  'enable',
@@ -155,7 +155,7 @@ var aliasProtocols = {
155
155
  var protocolsWithoutG = protocols.slice(1);
156
156
  var reqProtocols = protocols.filter(function (name) {
157
157
  return pureResProtocols.indexOf(name) === -1;
158
- });
158
+ }).concat(toolProtocols);
159
159
  var reqProtosWithoutG = reqProtocols.filter(function (name) {
160
160
  return name !== 'G';
161
161
  });
@@ -266,12 +266,6 @@ function resetRules(rules) {
266
266
 
267
267
  exports.resetRules = resetRules;
268
268
 
269
- function isResRule(protocol) {
270
- return resProtocols.indexOf(protocol) != -1;
271
- }
272
-
273
- exports.isResRule = isResRule;
274
-
275
269
  function isWebProtocol(protocol) {
276
270
  return protocol == 'http:' || protocol == 'https:';
277
271
  }