whistle 2.10.9 → 2.10.11

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.
Files changed (47) hide show
  1. package/assets/js/log.js +4 -0
  2. package/bin/api.js +3 -1
  3. package/bin/util.js +1 -1
  4. package/bin/whistle.js +5 -0
  5. package/biz/webui/cgi-bin/get-data.js +0 -1
  6. package/biz/webui/cgi-bin/init.js +0 -1
  7. package/biz/webui/cgi-bin/status.js +2 -1
  8. package/biz/webui/cgi-bin/util.js +1 -1
  9. package/biz/webui/cgi-bin/values/add.js +15 -13
  10. package/biz/webui/htdocs/index.html +1 -1
  11. package/biz/webui/htdocs/js/index.js +50 -51
  12. package/biz/webui/lib/index.js +39 -30
  13. package/index.js +10 -12
  14. package/lib/config.js +25 -79
  15. package/lib/handlers/file-proxy.js +1 -1
  16. package/lib/https/ca.js +18 -17
  17. package/lib/https/h2.js +54 -35
  18. package/lib/https/index.js +124 -107
  19. package/lib/inspectors/data.js +9 -3
  20. package/lib/inspectors/log.js +14 -33
  21. package/lib/inspectors/req.js +3 -6
  22. package/lib/inspectors/res.js +2 -5
  23. package/lib/inspectors/rules.js +11 -6
  24. package/lib/inspectors/weinre.js +1 -1
  25. package/lib/plugins/index.js +45 -54
  26. package/lib/plugins/load-plugin.js +31 -40
  27. package/lib/rules/dns.js +1 -1
  28. package/lib/rules/index.js +3 -1
  29. package/lib/rules/protocols.js +2 -4
  30. package/lib/rules/rules.js +3 -5
  31. package/lib/rules/util.js +2 -7
  32. package/lib/service/compose-data.js +2 -1
  33. package/lib/service/composer.js +12 -10
  34. package/lib/service/service.js +3 -5
  35. package/lib/socket-mgr.js +5 -2
  36. package/lib/tunnel.js +9 -5
  37. package/lib/util/common.js +190 -37
  38. package/lib/util/data-server.js +5 -1
  39. package/lib/util/drain.js +5 -6
  40. package/lib/util/file-mgr.js +1 -1
  41. package/lib/util/http-mgr.js +6 -2
  42. package/lib/util/index.js +48 -69
  43. package/lib/util/speed-transform.js +2 -2
  44. package/lib/util/transproto.js +4 -3
  45. package/lib/util/whistle-transform.js +2 -2
  46. package/lib/util/zlib.js +1 -1
  47. package/package.json +4 -4
@@ -8,6 +8,7 @@ var EventEmitter = require('events').EventEmitter;
8
8
  var LRU = require('lru-cache');
9
9
  var checkSNI = require('sni');
10
10
  var util = require('../util');
11
+ var common = require('../util/common');
11
12
  var extend = require('extend');
12
13
  var config = require('../config');
13
14
  var rules = require('../rules');
@@ -17,7 +18,7 @@ var hparser = require('hparser');
17
18
  var properties = require('../rules/util').properties;
18
19
  var ca = require('./ca');
19
20
  var loadCert = require('./load-cert');
20
- var h2Consts = config.enableH2 ? require('http2').constants : {};
21
+ var h2Consts = require('http2').constants;
21
22
 
22
23
  var STATUS_CODES = http.STATUS_CODES || {};
23
24
  var getRawHeaders = hparser.getRawHeaders;
@@ -1108,36 +1109,39 @@ var handlers = {
1108
1109
  server.emit('upgrade', req, socket);
1109
1110
  }
1110
1111
  };
1111
- var h2Handlers = config.enableH2
1112
- ? {
1113
- request: toHttp1,
1114
- upgrade: handlers.upgrade
1115
- }
1116
- : handlers;
1112
+ var h2Handlers = {
1113
+ request: toHttp1,
1114
+ upgrade: handlers.upgrade
1115
+ };
1117
1116
 
1118
1117
  var HTTP_RE = /^(\w+)\s+(\S+)\s+HTTP\/1.\d$/im;
1119
1118
  var HTTP2_RE = /^PRI\s\*\s+HTTP\/2.0$/im;
1120
1119
  var CONNECT_RE = /^CONNECT$/i;
1121
1120
 
1122
- function addClientInfo(socket, chunk, statusLine, clientIp, clientPort) {
1123
- var len = Buffer.byteLength(statusLine);
1124
- chunk = chunk.slice(len);
1125
- statusLine +=
1126
- '\r\n' +
1127
- config.CLIENT_INFO_HEADER +
1128
- ': ' +
1129
- clientIp +
1130
- ',' +
1131
- clientPort +
1132
- ',' +
1133
- socket._remoteAddr +
1134
- ',' +
1135
- socket._remotePort;
1121
+ function getTunnelHeaders(socket, statusLine, clientIp, clientPort, newHost) {
1122
+ var clientInfo = clientIp + ',' + clientPort + ',' + socket._remoteAddr + ',' + socket._remotePort;
1123
+ var headers = newHost ? {} : null;
1124
+ if (headers) {
1125
+ headers.host = newHost;
1126
+ headers[config.CLIENT_INFO_HEADER] = clientInfo;
1127
+ } else {
1128
+ statusLine += '\r\n' + config.CLIENT_INFO_HEADER + ': ' + clientInfo;
1129
+ }
1136
1130
  var tunnelData = getTunnelData(socket, clientIp, clientPort);
1137
1131
  if (tunnelData) {
1138
- statusLine += '\r\n' + util.TEMP_TUNNEL_DATA_HEADER + ': ' + encodeURIComponent(JSON.stringify(tunnelData));
1132
+ tunnelData = encodeURIComponent(JSON.stringify(tunnelData));
1133
+ if (headers) {
1134
+ headers[util.TEMP_TUNNEL_DATA_HEADER] = tunnelData;
1135
+ } else {
1136
+ statusLine += '\r\n' + util.TEMP_TUNNEL_DATA_HEADER + ': ' + tunnelData;
1137
+ }
1139
1138
  }
1140
- return Buffer.concat([Buffer.from(statusLine), chunk]);
1139
+ return headers || Buffer.from(statusLine);
1140
+ }
1141
+
1142
+ function addClientInfo(socket, chunk, statusLine, clientIp, clientPort) {
1143
+ chunk = chunk.slice(Buffer.byteLength(statusLine));
1144
+ return Buffer.concat([getTunnelHeaders(socket, statusLine, clientIp, clientPort), chunk]);
1141
1145
  }
1142
1146
 
1143
1147
  module.exports = function (socket, next, isWebPort) {
@@ -1177,6 +1181,12 @@ module.exports = function (socket, next, isWebPort) {
1177
1181
  headersStr = chunk && chunk.toString();
1178
1182
  var isHttp = chunk && HTTP_RE.test(headersStr);
1179
1183
  var statusLine = isHttp && RegExp['$&'];
1184
+ var handlePipe = function() {
1185
+ reqSocket.on('error', destroy);
1186
+ reqSocket.write(chunk);
1187
+ reqSocket.pipe(socket).pipe(reqSocket);
1188
+ socket.resume();
1189
+ };
1180
1190
  if (isHttp && CONNECT_RE.test(RegExp.$1)) {
1181
1191
  chunk = addClientInfo(socket, chunk, statusLine, clientIp, clientPort);
1182
1192
  util.connect(
@@ -1189,10 +1199,7 @@ module.exports = function (socket, next, isWebPort) {
1189
1199
  if (err || socket._hasError) {
1190
1200
  return destroy(err);
1191
1201
  }
1192
- reqSocket.on('error', destroy);
1193
- reqSocket.write(chunk);
1194
- reqSocket.pipe(socket).pipe(reqSocket);
1195
- socket.resume();
1202
+ handlePipe();
1196
1203
  }
1197
1204
  );
1198
1205
  return;
@@ -1212,105 +1219,115 @@ module.exports = function (socket, next, isWebPort) {
1212
1219
  addClientInfo(socket, chunk, statusLine, clientIp, clientPort)
1213
1220
  );
1214
1221
  }
1215
- } else if (isEnable('forHttp') || disable.captureHttps) {
1222
+ return;
1223
+ }
1224
+ if (isEnable('forHttp') || disable.captureHttps) {
1216
1225
  return next(chunk);
1217
- } else {
1218
- var isHttpH2 = HTTP2_RE.test(headersStr);
1219
- if (!isHttpH2 && chunk[0] != 22) {
1220
- return next(chunk);
1221
- }
1222
- var useSNI, domain, serverKey;
1223
- var handleConnect = function (port) {
1224
- var promise =
1226
+ }
1227
+ var isHttpH2 = HTTP2_RE.test(headersStr);
1228
+ if (!isHttpH2 && chunk[0] != 22) {
1229
+ return next(chunk);
1230
+ }
1231
+ var useSNI, domain, serverKey;
1232
+ var handleConnect = function (port) {
1233
+ var promise =
1225
1234
  !isHttpH2 && !useSNI && serverAgent.existsServer(serverKey);
1226
- var httpsServer = promise && promise.cert && promise.server;
1227
- if (httpsServer && httpsServer.setSecureContext) {
1228
- var cert = serverAgent.createCertificate(domain);
1229
- if (
1230
- cert.key !== promise.cert.key ||
1231
- cert.cert !== promise.cert.cert
1232
- ) {
1233
- try {
1234
- cert._ctx = cert._ctx || ca.createSecureContext(cert);
1235
- httpsServer.setSecureContext(cert._ctx);
1236
- promise.cert = cert;
1237
- } catch (e) {}
1238
- }
1235
+ var oldCert = promise && promise.cert;
1236
+ var httpsServer = oldCert && promise.server;
1237
+ if (httpsServer && httpsServer.setSecureContext) {
1238
+ var cert = serverAgent.createCertificate(domain);
1239
+ if (cert.key !== oldCert.key || cert.cert !== oldCert.cert) {
1240
+ try {
1241
+ cert._ctx = cert._ctx || ca.createSecureContext(cert);
1242
+ httpsServer.setSecureContext(cert._ctx);
1243
+ promise.cert = cert;
1244
+ } catch (e) {}
1239
1245
  }
1240
- util.connect(
1241
- {
1242
- port: port,
1243
- host: LOCALHOST,
1244
- localAddress: LOCALHOST
1245
- },
1246
+ }
1247
+ util.connect(
1248
+ {
1249
+ port: port,
1250
+ host: LOCALHOST,
1251
+ localAddress: LOCALHOST
1252
+ },
1246
1253
  function (err, s) {
1247
1254
  reqSocket = s;
1248
1255
  if (err || socket._hasError) {
1249
1256
  return destroy(err);
1250
1257
  }
1251
- reqSocket.on('error', destroy);
1252
- socket._w2TunnelKey = reqSocket.localPort + ':' + reqSocket.remotePort;
1253
- tunnelTmplData.set(socket._w2TunnelKey, getTunnelData(socket, clientIp, clientPort, isHttpH2));
1254
- reqSocket.write(chunk);
1255
- reqSocket.pipe(socket).pipe(reqSocket);
1256
- socket.resume();
1258
+ var key = reqSocket.localPort + ':' + reqSocket.remotePort;
1259
+ socket._w2TunnelKey = key;
1260
+ tunnelTmplData.set(key, getTunnelData(socket, clientIp, clientPort, isHttpH2));
1261
+ handlePipe();
1257
1262
  }
1258
1263
  );
1259
- };
1260
- var useNoSNIServer = function () {
1261
- serverKey = requestCert ? ':' + domain : domain;
1262
- serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
1263
- };
1264
+ };
1265
+ var useNoSNIServer = function () {
1266
+ serverKey = requestCert ? ':' + domain : domain;
1267
+ serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
1268
+ };
1264
1269
 
1265
- var handleRequest = function () {
1266
- if (useSNI) {
1267
- var disableH2 = !properties.isEnableHttp2();
1268
- if (disable.http2) {
1269
- disableH2 = true;
1270
- } else if (enable.http2) {
1271
- disableH2 = false;
1272
- }
1273
- getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
1274
- } else if (isHttpH2) {
1275
- getHttp2Server(h2Handlers, handleConnect);
1276
- } else {
1277
- useNoSNIServer();
1270
+ var handleRequest = function () {
1271
+ if (useSNI) {
1272
+ var disableH2 = !properties.isEnableHttp2();
1273
+ if (disable.http2) {
1274
+ disableH2 = true;
1275
+ } else if (enable.http2) {
1276
+ disableH2 = false;
1278
1277
  }
1279
- };
1280
- if (isHttpH2) {
1281
- return handleRequest();
1278
+ getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
1279
+ } else if (isHttpH2) {
1280
+ getHttp2Server(h2Handlers, handleConnect);
1281
+ } else {
1282
+ useNoSNIServer();
1282
1283
  }
1283
- useSNI = checkSNI(chunk);
1284
- var servername = useSNI || socket.tunnelHostname;
1285
- if (
1286
- !servername ||
1284
+ };
1285
+ if (isHttpH2) {
1286
+ return handleRequest();
1287
+ }
1288
+ useSNI = checkSNI(chunk);
1289
+ var servername = useSNI || socket.tunnelHostname;
1290
+ if (useSNI && socket._useSniAsTunnelDomain && useSNI !== socket.tunnelHostname) {
1291
+ var tunnelPort = socket.tunnelPort || 443;
1292
+ return common.connectInner({
1293
+ host: useSNI,
1294
+ port: tunnelPort,
1295
+ proxyHost: config.host || LOCALHOST,
1296
+ proxyPort: config.port,
1297
+ headers: getTunnelHeaders(socket, statusLine, clientIp, clientPort, useSNI + ':' + tunnelPort)
1298
+ }, function(s) {
1299
+ reqSocket = s;
1300
+ handlePipe();
1301
+ }, config).on('error', destroy);
1302
+ }
1303
+ if (
1304
+ !servername || socket._noCaptureW2 ||
1287
1305
  (useSNI ? disable.captureSNI : (disable.captureNoSNI || (net.isIP(servername) && !isCaptureIp()))) ||
1288
1306
  (socket.useProxifier && !ca.existsCustomCert(servername))
1289
1307
  ) {
1290
- return next(chunk);
1291
- }
1292
- var requestCert =
1308
+ return next(chunk);
1309
+ }
1310
+ var requestCert =
1293
1311
  (enable.clientCert || enable.requestCert) &&
1294
1312
  !disable.clientCert &&
1295
1313
  !disable.requestCert;
1296
- domain = getDomain(servername);
1297
- socket.curUrl = socket.fullUrl = 'https://' + servername;
1298
- socket.useSNI = useSNI;
1299
- socket.serverName = socket.servername = servername;
1300
- socket.commonName = domain;
1301
- loadCert(socket, function (cert) {
1302
- if (socket._hasError) {
1303
- return destroy();
1304
- }
1305
- if (cert === false) {
1306
- return next(chunk);
1307
- }
1308
- if (cert) {
1309
- domain = servername;
1310
- }
1311
- handleRequest();
1312
- });
1313
- }
1314
+ domain = getDomain(servername);
1315
+ socket.curUrl = socket.fullUrl = 'https://' + servername;
1316
+ socket.useSNI = useSNI;
1317
+ socket.serverName = socket.servername = servername;
1318
+ socket.commonName = domain;
1319
+ loadCert(socket, function (cert) {
1320
+ if (socket._hasError) {
1321
+ return destroy();
1322
+ }
1323
+ if (cert === false) {
1324
+ return next(chunk);
1325
+ }
1326
+ if (cert) {
1327
+ domain = servername;
1328
+ }
1329
+ handleRequest();
1330
+ });
1314
1331
  },
1315
1332
  isWebPort ? 0 : TIMEOUT
1316
1333
  );
@@ -197,6 +197,7 @@ function emitDataEvents(req, res, proxy) {
197
197
  var setRequestTime = function (time) {
198
198
  data.requestTime = time;
199
199
  data.connectTime = req._connectTime;
200
+ reqData.size = reqData.size || 0;
200
201
  };
201
202
  var setEndTime = function () {
202
203
  if (data.requestTime || !requestTime) {
@@ -205,6 +206,7 @@ function emitDataEvents(req, res, proxy) {
205
206
  } else if (endTime == null) {
206
207
  endTime = endTime || Date.now();
207
208
  }
209
+ resData.size = resData.size || 0;
208
210
  };
209
211
  var updateVersion = function () {
210
212
  if (req.useH2 != null) {
@@ -419,7 +421,7 @@ function emitDataEvents(req, res, proxy) {
419
421
  }
420
422
 
421
423
  req.once('dest', function (_req) {
422
- _req.once('finish', function () {
424
+ util.onWriteEnd(_req, function () {
423
425
  if (!requestTime) {
424
426
  setRequestTime(Date.now());
425
427
  }
@@ -441,15 +443,19 @@ function emitDataEvents(req, res, proxy) {
441
443
  req.once('error', handleError);
442
444
  res.once('error', handleError);
443
445
  res.once('close', handleError);
444
- res.once('finish', setEndTime);
446
+ util.onWriteEnd(res, setEndTime);
445
447
 
446
448
  function handleError(err) {
447
449
  req._hasError = true;
448
450
  util.clearDelayTimer(req);
449
- if (!data || endTime || data.endTime || (data.responseTime && !err)) {
451
+ if (!data || endTime || data.endTime) {
450
452
  return;
451
453
  }
454
+ // 触发 endTime
452
455
  !endTime && setEndTime();
456
+ if (data.responseTime && !err) {
457
+ return;
458
+ }
453
459
  delete data.abort;
454
460
  // 不能乱优化,跟 var msg = err && err.message; if (msg !== 'Aborted' && msg !== 'aborted') 不一样
455
461
  if (err && err.message !== 'Aborted' && err.message !== 'aborted') {
@@ -7,7 +7,6 @@ var logScriptFile = path.join(config.ASSESTS_PATH, 'js/log.js');
7
7
  var logScript = fs.readFileSync(logScriptFile, { encoding: 'utf8' });
8
8
  var logScriptTag = '<script>' + logScript + '</script>\r\n';
9
9
  var logHtmlScript = '<!DOCTYPE html>\r\n' + logScriptTag;
10
- var LOG_ID_RE = /^log:\/\/(\{[^\s]{1,36}\}|[^/\\{}()<>\s]{1,36})$/;
11
10
 
12
11
  function wrapScript(script, isHtml) {
13
12
  return isHtml
@@ -53,39 +52,21 @@ module.exports = function (req, res) {
53
52
  transform._transform = function (chunk, _, callback) {
54
53
  if (!added) {
55
54
  added = true;
56
- var logId = '';
57
- var isValue;
58
- if (LOG_ID_RE.test(log.matcher)) {
59
- logId = RegExp.$1;
60
- if (logId[0] === '{') {
61
- logId = logId.slice(1, -1);
62
- isValue = true;
63
- }
64
- try {
65
- logId = encodeURIComponent(logId);
66
- } catch (e) {}
67
- }
68
- util.getRuleValue(
69
- logId && !isValue ? null : log,
70
- function (script) {
71
- topScript = topScript.replace('$LOG_ID', logId);
72
- var buf = [util.toBuffer(topScript)];
73
- userScript = script || null;
74
- if (userScript) {
75
- userScript = util.toBuffer(wrapScript(userScript, isHtml));
76
- if (isHtml || !chunk) {
77
- buf.push(userScript);
78
- userScript = null;
79
- }
55
+ var logId = util.removeProtocol(log.matcher, true);
56
+ util.getRuleValue(!logId || /^[^/\\{}()<>]+$/.test(logId) ? null : log, function (script) {
57
+ topScript = topScript.replace('$LOG_ID', logId && util.encodeURIComponent(logId));
58
+ var buf = [util.toBuffer(topScript)];
59
+ userScript = script || null;
60
+ if (userScript) {
61
+ userScript = util.toBuffer(wrapScript(userScript, isHtml));
62
+ if (isHtml || !chunk) {
63
+ buf.push(userScript);
64
+ userScript = null;
80
65
  }
81
- chunk && buf.push(chunk);
82
- callback(null, Buffer.concat(buf));
83
- },
84
- null,
85
- null,
86
- null,
87
- req
88
- );
66
+ }
67
+ chunk && buf.push(chunk);
68
+ callback(null, Buffer.concat(buf));
69
+ }, null, null, null, req);
89
70
  } else {
90
71
  callback(null, chunk || userScript);
91
72
  }
@@ -502,8 +502,7 @@ module.exports = function (req, res, next) {
502
502
  }
503
503
 
504
504
  if (reqRules.method) {
505
- var method = util.getMatcherValue(reqRules.method);
506
- data.method = method;
505
+ data.method = util.getMatcherValue(reqRules.method);
507
506
  }
508
507
 
509
508
  if (reqRules.reqCharset) {
@@ -511,13 +510,11 @@ module.exports = function (req, res, next) {
511
510
  }
512
511
 
513
512
  if (reqRules.referer) {
514
- var referer = util.getMatcherValue(reqRules.referer);
515
- util.setHeader(data, 'referer', referer);
513
+ util.setHeader(data, 'referer', util.getMatcherValue(reqRules.referer));
516
514
  }
517
515
 
518
516
  if (reqRules.ua) {
519
- var ua = util.getMatcherValue(reqRules.ua);
520
- util.setHeader(data, 'user-agent', ua);
517
+ util.setHeader(data, 'user-agent', util.getMatcherValue(reqRules.ua));
521
518
  }
522
519
 
523
520
  var reqSpeed = util.getMatcherValue(reqRules.reqSpeed);
@@ -168,9 +168,6 @@ function readFirstChunk(req, res, src, cb) {
168
168
  }
169
169
 
170
170
  function checkH2(req, isHttps) {
171
- if (!config.enableH2) {
172
- return;
173
- }
174
171
  req.useH2 = req.isH2;
175
172
  var d = req.disable;
176
173
  var e = req.enable;
@@ -798,7 +795,7 @@ module.exports = function (req, res, next) {
798
795
  var useFrames;
799
796
  res.headers = req.resHeaders = headers;
800
797
  res._originEncoding = headers['content-encoding'];
801
- req.statusCode = _res.statusCode;
798
+ req.statusCode = res.statusCode = _res.statusCode;
802
799
  if (_res.rawHeaderNames) {
803
800
  res.rawHeaderNames = _res.rawHeaderNames;
804
801
  } else {
@@ -1243,7 +1240,7 @@ module.exports = function (req, res, next) {
1243
1240
  _res.statusCode,
1244
1241
  formatHeaders(curHeaders, rawNames)
1245
1242
  );
1246
- util.onResEnd(_res, function () {
1243
+ util.onReadEnd(_res, function () {
1247
1244
  var trailers = _res.trailers;
1248
1245
  if (
1249
1246
  !res.chunkedEncoding ||
@@ -61,6 +61,15 @@ function setupRules(req, next) {
61
61
  });
62
62
  }
63
63
 
64
+ function handleCodec(socket, enTrans, deTrans, handleError) {
65
+ enTrans.on('error', handleError);
66
+ deTrans.on('error', handleError);
67
+ deTrans.once('end', function() {
68
+ util.endSocket(socket);
69
+ });
70
+ enTrans.pipe(socket).pipe(deTrans);
71
+ }
72
+
64
73
  function getDecoder(obj) {
65
74
  return function (socket, callback) {
66
75
  var encoding = obj._originEncoding;
@@ -97,9 +106,7 @@ function getDecoder(obj) {
97
106
  delete obj.headers['content-length'];
98
107
  var enTrans = getEncodeTransform();
99
108
  var deTrans = getDecodeTransform();
100
- enTrans.pipe(socket).pipe(deTrans);
101
- enTrans.on('error', handleError);
102
- deTrans.on('error', handleError);
109
+ handleCodec(socket, enTrans, deTrans, handleError);
103
110
  if (decoder) {
104
111
  decoder.pipe(enTrans);
105
112
  } else {
@@ -127,9 +134,7 @@ function getEncoder(obj, req) {
127
134
  delete obj.headers['content-length'];
128
135
  var enTrans = getEncodeTransform();
129
136
  var deTrans = getDecodeTransform();
130
- enTrans.on('error', handleError);
131
- deTrans.on('error', handleError);
132
- enTrans.pipe(socket).pipe(deTrans);
137
+ handleCodec(socket, enTrans, deTrans, handleError);
133
138
  socket = enTrans;
134
139
  if (encoder) {
135
140
  deTrans.pipe(encoder);
@@ -36,7 +36,7 @@ module.exports = function (req, res) {
36
36
  }
37
37
  !util.isEnable(req, 'keepAllCSP') && util.disableCSP(_res.headers);
38
38
  !req._customCache && util.disableResStore(_res.headers);
39
- var name = util.getPath(util.rule.getMatcher(weinre));
39
+ var name = util.removeProtocol(weinre.matcher, true);
40
40
  var transform = new Transform();
41
41
  transform._transform = function (chunk, _, callback) {
42
42
  if (!chunk) {
@@ -289,8 +289,8 @@ pluginMgr.on('uninstall', function (result) {
289
289
  });
290
290
  });
291
291
 
292
- function formatMTime(mtime) {
293
- return '[' + (new Date(mtime).toLocaleTimeString()) + ']';
292
+ function showUpdateInfo(action, name) {
293
+ return '[' + (new Date().toLocaleTimeString()) + '] ' + action + ' ' + name.slice(0, -1);
294
294
  }
295
295
 
296
296
  function showVerbose(oldData, newData) {
@@ -319,30 +319,15 @@ function showVerbose(oldData, newData) {
319
319
 
320
320
  uninstallData &&
321
321
  Object.keys(uninstallData).forEach(function (name) {
322
- console.log(
323
- colors.red(
324
- formatMTime(uninstallData[name].mtime) +
325
- ' UNINSTALL ' + name.slice(0, -1)
326
- )
327
- );
322
+ console.log(colors.red(showUpdateInfo('UNINSTALL', name)));
328
323
  });
329
324
  installData &&
330
325
  Object.keys(installData).forEach(function (name) {
331
- console.log(
332
- colors.green(
333
- formatMTime(installData[name].mtime) +
334
- ' INSTALL ' + name.slice(0, -1)
335
- )
336
- );
326
+ console.log(colors.green(showUpdateInfo('INSTALL', name)));
337
327
  });
338
328
  updateData &&
339
329
  Object.keys(updateData).forEach(function (name) {
340
- console.log(
341
- colors.yellow(
342
- formatMTime(updateData[name].mtime) +
343
- ' UPDATE ' + name.slice(0, -1)
344
- )
345
- );
330
+ console.log(colors.yellow(showUpdateInfo('UPDATE', name)));
346
331
  });
347
332
  }
348
333
 
@@ -1155,6 +1140,10 @@ function emptyFilter(val) {
1155
1140
  return !!val;
1156
1141
  }
1157
1142
 
1143
+ function isClosed(req) {
1144
+ return req._hasClosed || req._hasError;
1145
+ }
1146
+
1158
1147
  function getRulesMgr(type, req, res, callback) {
1159
1148
  var plugins = req.whistlePlugins;
1160
1149
  if (!plugins) {
@@ -1170,14 +1159,29 @@ function getPluginRulesCallback(req, callback) {
1170
1159
  };
1171
1160
  }
1172
1161
 
1162
+ function resolvePipe(req, m1, m2) {
1163
+ if (req.isPluginReq) {
1164
+ return;
1165
+ }
1166
+ var filter = m1 && m1.resolveFilter(req);
1167
+ if (m2) {
1168
+ var filter2 = m2.resolveFilter(req);
1169
+ filter = filter ? extend(filter, filter2) : filter2;
1170
+ }
1171
+ if (util.isIgnored(filter, 'pipe')) {
1172
+ return;
1173
+ }
1174
+ return (m1 && m1.resolvePipe(req)) || (m2 && m2.resolvePipe(req));
1175
+ }
1176
+
1173
1177
  function resolvePipePlugin(req, callback) {
1174
1178
  if (req._pipePlugin == null) {
1175
1179
  var pipe;
1176
1180
  var hRules = req.headerRulesMgr;
1177
1181
  if (config.multiEnv) {
1178
- pipe = (hRules && hRules.resolvePipe(req)) || rulesMgr.resolvePipe(req);
1182
+ pipe = resolvePipe(req, hRules, rulesMgr);
1179
1183
  } else {
1180
- pipe = rulesMgr.resolvePipe(req) || (hRules && hRules.resolvePipe(req));
1184
+ pipe = resolvePipe(req, rulesMgr, hRules);
1181
1185
  }
1182
1186
  var plugin;
1183
1187
  req._pipeRule = pipe;
@@ -1205,7 +1209,7 @@ function getPipe(type, hookName) {
1205
1209
  }
1206
1210
  resolvePipePlugin(req, function (ports) {
1207
1211
  var port = ports && ports[type + 'Port'];
1208
- if (!port || req._hasClosed || req._hasError) {
1212
+ if (!port || isClosed(req)) {
1209
1213
  return callback();
1210
1214
  }
1211
1215
  var options = getOptions(req, res, isRes && 'resRules');
@@ -1232,46 +1236,33 @@ function getPipe(type, hookName) {
1232
1236
  delete req.headers['sec-websocket-extensions'];
1233
1237
  }
1234
1238
  }
1235
- var client;
1236
1239
  var done;
1237
- var handleConnect = function (socket, _res) {
1240
+ var handleConnect = function (socket) {
1238
1241
  if (!done) {
1239
1242
  done = true;
1240
- if (req._hasError) {
1241
- return socket.destroy();
1243
+ if (isClosed(req)) {
1244
+ return util.endSocket(socket);
1242
1245
  }
1246
+ req.once('_closed', function () {
1247
+ util.endSocket(socket);
1248
+ });
1243
1249
  callback(socket);
1250
+ } else if (socket) {
1251
+ util.endSocket(socket);
1244
1252
  }
1245
1253
  };
1246
- var destroy = function () {
1247
- if (client) {
1248
- client.destroy();
1249
- client.socket && client.socket.destroy();
1250
- client = null;
1251
- handleConnect();
1252
- }
1253
- };
1254
- var handleError = function (err) {
1255
- if (client) {
1256
- destroy();
1257
- if (err) {
1258
- debugMode && console.log(req._pipeRule.matcher, type);
1259
- (res || req).emit('error', err);
1260
- }
1261
- }
1262
- };
1263
- client = config.connect(options, handleConnect);
1264
- client.on('error', function () {
1265
- if (client) {
1266
- destroy();
1267
- client = !req._hasError && config.connect(options, handleConnect);
1268
- client && util.onSocketEnd(client, handleError);
1254
+ var client = config.connect(options, handleConnect);
1255
+ client.once('error', function () {
1256
+ if (!done && !req._hasError) {
1257
+ client = config.connect(options, handleConnect);
1258
+ client.once('error', function (err) {
1259
+ if (!done && !isClosed(req)) {
1260
+ debugMode && console.log(type, err);
1261
+ (res || req).emit('error', err);
1262
+ }
1263
+ });
1269
1264
  }
1270
1265
  });
1271
- req.once('_closed', function() {
1272
- handleConnect();
1273
- destroy();
1274
- });
1275
1266
  });
1276
1267
  };
1277
1268
  }