whistle 2.10.10 → 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.
package/index.js CHANGED
@@ -8,7 +8,6 @@ var os = require('os');
8
8
  var assert = require('assert');
9
9
  var common = require('./lib/util/common');
10
10
 
11
- var ver = process.version.substring(1).split('.');
12
11
  var PROD_RE = /(^|\|)prod(uction)?($|\|)/;
13
12
  var noop = function () {};
14
13
  var state = {};
@@ -16,21 +15,20 @@ var INTERVAL = 1000;
16
15
  var TIMEOUT = 10000;
17
16
  var MASTER_TIMEOUT = 12000;
18
17
 
19
- if (ver[0] >= 7 && ver[1] >= 7) {
20
- var connect = net.Socket.prototype.connect;
21
- if (typeof connect === 'function') {
22
- //fix: Node v7.7.0+引入的 `"listener" argument must be a function` 问题
23
- net.Socket.prototype.connect = function (options, cb) {
24
- if (options && typeof options === 'object' && typeof cb !== 'function') {
25
- return connect.call(this, options, null);
26
- }
27
- return connect.apply(this, arguments);
28
- };
29
- }
18
+ var connect = net.Socket.prototype.connect;
19
+ if (typeof connect === 'function') {
20
+ //fix: Node v7.7.0+引入的 `"listener" argument must be a function` 问题
21
+ net.Socket.prototype.connect = function (options, cb) {
22
+ if (options && typeof options === 'object' && typeof cb !== 'function') {
23
+ return connect.call(this, options, null);
24
+ }
25
+ return connect.apply(this, arguments);
26
+ };
30
27
  }
31
28
 
32
29
  var env = process.env || '';
33
30
  env.WHISTLE_ROOT = __dirname;
31
+ env.PFORK_MAX_HTTP_HEADER_SIZE = 1024 * 1024;
34
32
  if (typeof tls.checkServerIdentity == 'function') {
35
33
  var checkServerIdentity = tls.checkServerIdentity;
36
34
  tls.checkServerIdentity = function () {
package/lib/config.js CHANGED
@@ -1,12 +1,11 @@
1
1
  var path = require('path');
2
- var http = require('http');
3
2
  var fs = require('fs');
4
3
  var net = require('net');
5
4
  var dns = require('dns');
6
5
  var qs = require('querystring');
7
6
  var LRU = require('lru-cache');
8
- var httpAgent = http.Agent;
9
- var httpsAgent = require('https').Agent;
7
+ var HttpAgent = require('http').Agent;
8
+ var HttpsAgent = require('https').Agent;
10
9
  var parseUrl = require('./util/parse-url-safe');
11
10
  var fse = require('fs-extra2');
12
11
  var extend = require('extend');
@@ -25,13 +24,11 @@ var CMD_RE = /^[\w]{1,12}(?:\s+-g)?$/;
25
24
  var httpsAgents = new LRU({ max: 360 });
26
25
  var socksAgents = new LRU({ max: 100 });
27
26
  var version = process.version.substring(1).split('.');
28
- var disableAgent = version[0] > 10;
29
- var hasIPv6First = version[0] >= 22 && version[1] >= 1;
27
+ var hasIPv6First = (version[0] === 22 && version[1] >= 1) || version[0] > 22;
30
28
  var hasDnsOrder = typeof dns.setDefaultResultOrder === 'function';
31
29
  var uid = Date.now().toString(16) + (process.pid * 10000 + Math.floor(Math.random() * 10000)).toString(16);
32
30
  var IPV4_RE = /^([\d.]+)(:\d{1,5})?$/;
33
31
  var IPV6_RE = /^\[([\w:]+)\](:\d{1,5})?$/;
34
- var noop = function () {};
35
32
  var DATA_KEY_RE = /^(clientip|clientid|tunneldata)([=.])([\w.-]+)$/i;
36
33
  var DNS_ORDERS = ['ipv4First', 'ipv4first', 'ipv6first', 'ipv6First', 'verbatim'];
37
34
  var LOCAL_UI_HOST_LIST = [
@@ -66,7 +63,6 @@ if (hasDnsOrder) {
66
63
  config.appName = common.upperFirst(config.name);
67
64
  config.uid = uid;
68
65
  config.rejectUnauthorized = false;
69
- config.enableH2 = version[0] > 12; // 支持 HTTP2 要求的最低 Node 版本
70
66
  config.ASSESTS_PATH = path.join(__dirname, '../assets');
71
67
  config.WHISTLE_POLICY_HEADER = 'x-whistle-policy';
72
68
  config.CLIENT_IP_HEADER = common.CLIENT_IP_HEADER;
@@ -120,9 +116,11 @@ config.CONN_TIMEOUT = CONN_TIMEOUT;
120
116
 
121
117
  var getWhistlePath = common.getWhistlePath;
122
118
  var getHostPort = common.getHostPort;
119
+ var WHISTLE_PATH = getWhistlePath();
123
120
 
124
- var ALL_WHISTLES_PATH = path.join(getWhistlePath(), 'all_whistles');
121
+ var ALL_WHISTLES_PATH = path.join(WHISTLE_PATH, 'all_whistles');
125
122
 
123
+ config.WHISTLE_PATH = WHISTLE_PATH;
126
124
 
127
125
  function domainToRegExp(_, star, dot) {
128
126
  var len = star.length;
@@ -137,16 +135,16 @@ function domainToRegExp(_, star, dot) {
137
135
  }
138
136
 
139
137
  function getDataDir(dirname) {
140
- var dir = path.join(getWhistlePath(), dirname || '.' + config.name);
138
+ var dir = path.join(WHISTLE_PATH, dirname || '.' + config.name);
141
139
  fse.ensureDirSync(dir);
142
140
  return dir;
143
141
  }
144
142
 
145
143
  config.baseDir = getDataDir();
146
- config.CUSTOM_PLUGIN_PATH = path.join(getWhistlePath(), 'custom_plugins');
147
- config.CUSTOM_CERTS_DIR = path.resolve(getWhistlePath(), 'custom_certs');
148
- config.SAVED_SESSIONS_PATH = path.resolve(getWhistlePath(), 'saved_sessions');
149
- config.DEV_PLUGINS_PATH = path.resolve(getWhistlePath(), 'dev_plugins');
144
+ config.CUSTOM_PLUGIN_PATH = path.join(WHISTLE_PATH, 'custom_plugins');
145
+ config.CUSTOM_CERTS_DIR = path.resolve(WHISTLE_PATH, 'custom_certs');
146
+ config.SAVED_SESSIONS_PATH = path.resolve(WHISTLE_PATH, 'saved_sessions');
147
+ config.DEV_PLUGINS_PATH = path.resolve(WHISTLE_PATH, 'dev_plugins');
150
148
  config.rulesDir = path.join(config.baseDir, 'rules');
151
149
  config.valuesDir = path.join(config.baseDir, 'values');
152
150
  config.propertiesDir = path.join(config.baseDir, 'properties');
@@ -167,55 +165,6 @@ try {
167
165
 
168
166
  exports.getWhistlePath = getWhistlePath;
169
167
  exports.getDataDir = getDataDir;
170
- var async_id_symbol;
171
- if (version[0] < 16) {
172
- try {
173
- async_id_symbol = process.binding('async_wrap').async_id_symbol;
174
- } catch (e) {}
175
- }
176
- var emptyHandle = {
177
- asyncReset: noop,
178
- getAsyncId: noop
179
- };
180
-
181
- function createAgent(agentConfig, https) {
182
- var agent = new (https ? httpsAgent : httpAgent)(agentConfig);
183
- if (async_id_symbol) {
184
- var addRequest = agent.addRequest;
185
- agent.addRequest = function (req, options) {
186
- // fix: https://github.com/nodejs/node/issues/13539
187
- var freeSockets = this.freeSockets[this.getName(options)];
188
- if (freeSockets && freeSockets.length) {
189
- var socket = freeSockets[0];
190
- var handle = socket._handle;
191
- if (!handle) {
192
- socket._handle = emptyHandle;
193
- } else if (typeof handle.asyncReset !== 'function') {
194
- handle.asyncReset = noop;
195
- }
196
- var originalRef = socket.ref;
197
- socket.ref = function () {
198
- socket.ref = originalRef;
199
- if (socket._handle === emptyHandle) {
200
- delete socket._handle;
201
- } else if (socket._handle.asyncReset === noop) {
202
- delete socket._handle.asyncReset;
203
- }
204
- socket.ref();
205
- };
206
- }
207
- var onSocket = req.onSocket;
208
- req.onSocket = function (socket) {
209
- try {
210
- socket[async_id_symbol] = socket._handle.getAsyncId();
211
- } catch (e) {}
212
- onSocket.apply(this, arguments);
213
- };
214
- addRequest.apply(this, arguments);
215
- };
216
- }
217
- return agent;
218
- }
219
168
 
220
169
  function getHttpsAgent(options, reqOpts) {
221
170
  var key = getCacheKey(options);
@@ -1093,10 +1042,10 @@ exports.extend = function (newConf) {
1093
1042
  keepAliveMsecs: KEEP_ALIVE_MSECS,
1094
1043
  maxFreeSockets: 0
1095
1044
  };
1096
- // node 11及以上版本缓存连接有问题,先禁掉
1097
- disableAgent = !newAgentConf && !useAgent && (disableAgent || config.debug);
1098
- config.httpAgent = disableAgent ? false : createAgent(agentConfig);
1099
- config.httpsAgent = disableAgent ? false : createAgent(agentConfig, true);
1045
+ // node 11及以上版本缓存连接有问题,默认禁掉
1046
+ var disableAgent = !newAgentConf && !useAgent;
1047
+ config.httpAgent = disableAgent ? false : new HttpAgent(agentConfig);
1048
+ config.httpsAgent = disableAgent ? false : new HttpsAgent(agentConfig);
1100
1049
  config.getSocksAgent = function (options) {
1101
1050
  var key = getCacheKey(options, true);
1102
1051
  var agent = socksAgents.get(key);
package/lib/https/ca.js CHANGED
@@ -691,7 +691,7 @@ exports.getHttp2Server = function (listener, callback) {
691
691
  };
692
692
 
693
693
  exports.getSNIServer = function (listener, callback, disableH2, requestCert) {
694
- var enableH2 = config.enableH2 && !disableH2;
694
+ var enableH2 = !disableH2;
695
695
  var name = (enableH2 ? 'h2Sni' : 'sni') + (requestCert ? 'WithCert' : '');
696
696
  var curPort = ports[name];
697
697
  if (curPort) {
package/lib/https/h2.js CHANGED
@@ -5,7 +5,7 @@ var sockx = require('sockx');
5
5
  var util = require('../util');
6
6
  var config = require('../config');
7
7
  var extend = require('extend');
8
- var http2 = config.enableH2 ? require('http2') : null;
8
+ var http2 = require('http2');
9
9
 
10
10
  var SUPPORTED_PROTOS = ['h2', 'http/1.1', 'http/1.0'];
11
11
  var H2_SETTINGS = { enablePush: false };
@@ -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) {
@@ -1215,37 +1219,37 @@ module.exports = function (socket, next, isWebPort) {
1215
1219
  addClientInfo(socket, chunk, statusLine, clientIp, clientPort)
1216
1220
  );
1217
1221
  }
1218
- } else if (isEnable('forHttp') || disable.captureHttps) {
1222
+ return;
1223
+ }
1224
+ if (isEnable('forHttp') || disable.captureHttps) {
1219
1225
  return next(chunk);
1220
- } else {
1221
- var isHttpH2 = HTTP2_RE.test(headersStr);
1222
- if (!isHttpH2 && chunk[0] != 22) {
1223
- return next(chunk);
1224
- }
1225
- var useSNI, domain, serverKey;
1226
- var handleConnect = function (port) {
1227
- 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 =
1228
1234
  !isHttpH2 && !useSNI && serverAgent.existsServer(serverKey);
1229
- var httpsServer = promise && promise.cert && promise.server;
1230
- if (httpsServer && httpsServer.setSecureContext) {
1231
- var cert = serverAgent.createCertificate(domain);
1232
- if (
1233
- cert.key !== promise.cert.key ||
1234
- cert.cert !== promise.cert.cert
1235
- ) {
1236
- try {
1237
- cert._ctx = cert._ctx || ca.createSecureContext(cert);
1238
- httpsServer.setSecureContext(cert._ctx);
1239
- promise.cert = cert;
1240
- } catch (e) {}
1241
- }
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) {}
1242
1245
  }
1243
- util.connect(
1244
- {
1245
- port: port,
1246
- host: LOCALHOST,
1247
- localAddress: LOCALHOST
1248
- },
1246
+ }
1247
+ util.connect(
1248
+ {
1249
+ port: port,
1250
+ host: LOCALHOST,
1251
+ localAddress: LOCALHOST
1252
+ },
1249
1253
  function (err, s) {
1250
1254
  reqSocket = s;
1251
1255
  if (err || socket._hasError) {
@@ -1257,61 +1261,73 @@ module.exports = function (socket, next, isWebPort) {
1257
1261
  handlePipe();
1258
1262
  }
1259
1263
  );
1260
- };
1261
- var useNoSNIServer = function () {
1262
- serverKey = requestCert ? ':' + domain : domain;
1263
- serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
1264
- };
1264
+ };
1265
+ var useNoSNIServer = function () {
1266
+ serverKey = requestCert ? ':' + domain : domain;
1267
+ serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
1268
+ };
1265
1269
 
1266
- var handleRequest = function () {
1267
- if (useSNI) {
1268
- var disableH2 = !properties.isEnableHttp2();
1269
- if (disable.http2) {
1270
- disableH2 = true;
1271
- } else if (enable.http2) {
1272
- disableH2 = false;
1273
- }
1274
- getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
1275
- } else if (isHttpH2) {
1276
- getHttp2Server(h2Handlers, handleConnect);
1277
- } else {
1278
- 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;
1279
1277
  }
1280
- };
1281
- if (isHttpH2) {
1282
- return handleRequest();
1278
+ getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
1279
+ } else if (isHttpH2) {
1280
+ getHttp2Server(h2Handlers, handleConnect);
1281
+ } else {
1282
+ useNoSNIServer();
1283
1283
  }
1284
- useSNI = checkSNI(chunk);
1285
- var servername = useSNI || socket.tunnelHostname;
1286
- if (
1287
- !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 ||
1288
1305
  (useSNI ? disable.captureSNI : (disable.captureNoSNI || (net.isIP(servername) && !isCaptureIp()))) ||
1289
1306
  (socket.useProxifier && !ca.existsCustomCert(servername))
1290
1307
  ) {
1291
- return next(chunk);
1292
- }
1293
- var requestCert =
1308
+ return next(chunk);
1309
+ }
1310
+ var requestCert =
1294
1311
  (enable.clientCert || enable.requestCert) &&
1295
1312
  !disable.clientCert &&
1296
1313
  !disable.requestCert;
1297
- domain = getDomain(servername);
1298
- socket.curUrl = socket.fullUrl = 'https://' + servername;
1299
- socket.useSNI = useSNI;
1300
- socket.serverName = socket.servername = servername;
1301
- socket.commonName = domain;
1302
- loadCert(socket, function (cert) {
1303
- if (socket._hasError) {
1304
- return destroy();
1305
- }
1306
- if (cert === false) {
1307
- return next(chunk);
1308
- }
1309
- if (cert) {
1310
- domain = servername;
1311
- }
1312
- handleRequest();
1313
- });
1314
- }
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
+ });
1315
1331
  },
1316
1332
  isWebPort ? 0 : TIMEOUT
1317
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) {
@@ -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;
@@ -1237,7 +1237,7 @@ function getPipe(type, hookName) {
1237
1237
  }
1238
1238
  }
1239
1239
  var done;
1240
- var handleConnect = function (socket, _res) {
1240
+ var handleConnect = function (socket) {
1241
1241
  if (!done) {
1242
1242
  done = true;
1243
1243
  if (isClosed(req)) {
@@ -387,6 +387,7 @@ function getScriptContext(req, res, body, pattern, frameOpts) {
387
387
  }
388
388
  if (frameOpts) {
389
389
  ctx.ctx = {
390
+ destroy: frameOpts.destroy,
390
391
  sendToServer: frameOpts.sendToServer,
391
392
  sendToClient: frameOpts.sendToClient,
392
393
  handleSendToClientFrame: null,
@@ -435,7 +436,7 @@ function getReqPayload(req, res, cb) {
435
436
 
436
437
  function execRulesScript(script, req, res, body, pattern, frameOpts) {
437
438
  var context = getScriptContext(req, res, body, pattern, frameOpts);
438
- if (!util.execScriptSync(script, context)) {
439
+ if (!util.runInContext(script, context)) {
439
440
  return '';
440
441
  }
441
442
  if (frameOpts) {
@@ -272,12 +272,10 @@ function isWebProtocol(protocol) {
272
272
 
273
273
  exports.isWebProtocol = isWebProtocol;
274
274
 
275
- function isWebsocketProtocol(protocol) {
275
+ function isWsProtocol(protocol) {
276
276
  return protocol == 'ws:' || protocol == 'wss:';
277
277
  }
278
278
 
279
- exports.isWebsocketProtocol = isWebsocketProtocol;
280
-
281
279
  function isFileProxy(protocol) {
282
280
  return RULE_RE.test(protocol) || LOC_RE.test(protocol);
283
281
  }
@@ -298,7 +296,7 @@ function contains(name) {
298
296
  }
299
297
  name += ':';
300
298
  return (
301
- isWebsocketProtocol(name) ||
299
+ isWsProtocol(name) ||
302
300
  isWebProtocol(name) ||
303
301
  isFileProxy(name) ||
304
302
  name == 'tunnel:'
@@ -54,10 +54,8 @@ var REG_URL_SYMBOL_RE = /^(\^+)/;
54
54
  var PATTERN_FILTER_RE = /^(?:filter|ignore):\/\/(.+)\/(i)?$/;
55
55
  var LINE_PROPS_RE = /^lineProps:\/\/(.*)$/;
56
56
  var FILTER_RE = /^(?:excludeFilter|includeFilter):\/\/(.*)$/;
57
- var PROPS_FILTER_RE =
58
- /^(?:filter|excludeFilter|includeFilter|ignore):\/\/(m(?:ethod)?|i(?:p)?|h(?:eader)?|env|s(?:tatusCode)?|from|b(?:ody)?|clientIp|clientIP|clientPort|remoteAddress|remotePort|serverIp|serverIP|serverPort|chance|probability|re[qs](?:H(?:eaders?)?)?):(.+)$/;
59
- var PURE_FILTER_RE =
60
- /^(?:excludeFilter|includeFilter):\/\/(statusCode|from|env|clientIp|clientIP|clientPort|remoteAddress|remotePort|serverIp|serverIP|chance|probability|serverPort|host|re[qs](?:H(?:eaders?)?)?)[.=](.+)$/;
57
+ var PROPS_FILTER_RE = /^(?:filter|excludeFilter|includeFilter|ignore):\/\/(m(?:ethod)?|i(?:p)?|h(?:eader)?|env|s(?:tatusCode)?|sni|from|b(?:ody)?|clientIp|clientIP|clientPort|remoteAddress|remotePort|serverIp|serverIP|serverPort|chance|probability|host|re[qs](?:H(?:eaders?)?)?)[:=](.+)$/;
58
+ var PURE_FILTER_RE = /^(?:excludeFilter|includeFilter):\/\/(re[qs](?:H(?:eaders?)?)?)\.(.+)$/;
61
59
  var PATTERN_WILD_FILTER_RE = /^(?:filter|ignore):\/\/(!)?(\*+\/)/;
62
60
  var INLINE_RE = /^((?:filter|excludeFilter|includeFilter|ignore):\/\/)(\(.*\)|\<.*\>)$/;
63
61
  var CHROME_PATH_RE = /^file:\/\/\/[A-Z]:\//;
@@ -22,8 +22,9 @@ exports = module.exports = function(req, res) {
22
22
  } else {
23
23
  cache.set(reqId, '');
24
24
  }
25
+ curBuf = curBuf.toString('base64');
25
26
  }
26
- result[reqId] = curBuf ? curBuf.toString('base64') : curBuf;
27
+ result[reqId] = curBuf;
27
28
  });
28
29
  res.json(result);
29
30
  };
@@ -154,10 +154,7 @@ function handleConnect(options, cb, count, testId) {
154
154
  proxyHost: PROXY_OPTS.host,
155
155
  proxyPort: PROXY_OPTS.port,
156
156
  headers: options.headers
157
- }, function(socket, svrRes, err) {
158
- if (err) {
159
- return handleCallback(execCb, err, null, testId);
160
- }
157
+ }, function(socket, svrRes) {
161
158
  if (TLS_PROTOS.indexOf(options.protocol) !== -1) {
162
159
  socket = tls.connect({
163
160
  rejectUnauthorized: config.rejectUnauthorized,
@@ -171,7 +168,7 @@ function handleConnect(options, cb, count, testId) {
171
168
  socket.write(data);
172
169
  options.body = data = null;
173
170
  }
174
- handleCallback(execCb, err, svrRes, testId);
171
+ handleCallback(execCb, null, svrRes, testId);
175
172
  }, config).on('error', execCb || noop);
176
173
  }
177
174
  }
@@ -277,8 +274,9 @@ function handleHttp(options, cb, count, reqId, testId) {
277
274
  }
278
275
  clearTimeout(timer);
279
276
  var headers = svrRes.headers;
280
- if (typeof headers.trailer === 'string' && headers.trailer.indexOf(',') !== -1) {
281
- headers.trailer = headers.trailer.split(',');
277
+ var trailer = headers.trailer;
278
+ if (typeof trailer === 'string' && trailer.indexOf(',') !== -1) {
279
+ headers.trailer = trailer.split(',');
282
280
  }
283
281
  var result = {
284
282
  statusCode: svrRes.statusCode,
package/lib/socket-mgr.js CHANGED
@@ -657,6 +657,9 @@ function getFrameSender(options, toServer) {
657
657
  function getFrameCtx(options, callback) {
658
658
  var req = options.req;
659
659
  rules.getFrameScriptCtx(req.rules.frameScript, req, options.res, {
660
+ destroy: function() {
661
+ destroy(options.reqId);
662
+ },
660
663
  sendToClient: getFrameSender(options),
661
664
  sendToServer: getFrameSender(options, true)
662
665
  }, callback);
@@ -703,7 +706,7 @@ exports.handleUpgrade = function (req, res) {
703
706
  resTrans.on('error', emitError);
704
707
  res.headers = res.headers || {};
705
708
  req.wsExts = res.headers['sec-websocket-extensions'] || '';
706
- var options = { req: req, res: res };
709
+ var options = { req: req, res: res, reqId: reqId };
707
710
  pluginMgr.getWsPipe(
708
711
  req,
709
712
  res,