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/bin/api.js +1 -83
- package/bin/whistle.js +5 -0
- package/biz/webui/cgi-bin/get-data.js +0 -1
- package/biz/webui/cgi-bin/init.js +0 -1
- package/biz/webui/cgi-bin/status.js +2 -1
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +48 -48
- package/index.js +10 -12
- package/lib/config.js +15 -66
- package/lib/https/ca.js +1 -1
- package/lib/https/h2.js +1 -1
- package/lib/https/index.js +113 -97
- package/lib/inspectors/data.js +2 -0
- package/lib/inspectors/req.js +3 -6
- package/lib/inspectors/res.js +0 -3
- package/lib/plugins/index.js +1 -1
- package/lib/rules/index.js +2 -1
- package/lib/rules/protocols.js +2 -4
- package/lib/rules/rules.js +2 -4
- package/lib/service/compose-data.js +2 -1
- package/lib/service/composer.js +5 -7
- package/lib/socket-mgr.js +4 -1
- package/lib/tunnel.js +9 -5
- package/lib/util/common.js +142 -12
- package/lib/util/index.js +19 -46
- package/package.json +3 -3
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
9
|
-
var
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
147
|
-
config.CUSTOM_CERTS_DIR = path.resolve(
|
|
148
|
-
config.SAVED_SESSIONS_PATH = path.resolve(
|
|
149
|
-
config.DEV_PLUGINS_PATH = path.resolve(
|
|
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
|
|
1098
|
-
config.httpAgent = disableAgent ? false :
|
|
1099
|
-
config.httpsAgent = disableAgent ? false :
|
|
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 =
|
|
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 =
|
|
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 };
|
package/lib/https/index.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
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
|
|
1123
|
-
var
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
config.CLIENT_INFO_HEADER
|
|
1128
|
-
|
|
1129
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
if (isEnable('forHttp') || disable.captureHttps) {
|
|
1219
1225
|
return next(chunk);
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
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
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
)
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
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
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
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
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1264
|
+
};
|
|
1265
|
+
var useNoSNIServer = function () {
|
|
1266
|
+
serverKey = requestCert ? ':' + domain : domain;
|
|
1267
|
+
serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
|
|
1268
|
+
};
|
|
1265
1269
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
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
|
-
|
|
1278
|
+
getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
|
|
1279
|
+
} else if (isHttpH2) {
|
|
1280
|
+
getHttp2Server(h2Handlers, handleConnect);
|
|
1281
|
+
} else {
|
|
1282
|
+
useNoSNIServer();
|
|
1283
1283
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
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
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1308
|
+
return next(chunk);
|
|
1309
|
+
}
|
|
1310
|
+
var requestCert =
|
|
1294
1311
|
(enable.clientCert || enable.requestCert) &&
|
|
1295
1312
|
!disable.clientCert &&
|
|
1296
1313
|
!disable.requestCert;
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
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
|
);
|
package/lib/inspectors/data.js
CHANGED
|
@@ -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) {
|
package/lib/inspectors/req.js
CHANGED
|
@@ -502,8 +502,7 @@ module.exports = function (req, res, next) {
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
if (reqRules.method) {
|
|
505
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|
package/lib/inspectors/res.js
CHANGED
package/lib/plugins/index.js
CHANGED
package/lib/rules/index.js
CHANGED
|
@@ -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.
|
|
439
|
+
if (!util.runInContext(script, context)) {
|
|
439
440
|
return '';
|
|
440
441
|
}
|
|
441
442
|
if (frameOpts) {
|
package/lib/rules/protocols.js
CHANGED
|
@@ -272,12 +272,10 @@ function isWebProtocol(protocol) {
|
|
|
272
272
|
|
|
273
273
|
exports.isWebProtocol = isWebProtocol;
|
|
274
274
|
|
|
275
|
-
function
|
|
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
|
-
|
|
299
|
+
isWsProtocol(name) ||
|
|
302
300
|
isWebProtocol(name) ||
|
|
303
301
|
isFileProxy(name) ||
|
|
304
302
|
name == 'tunnel:'
|
package/lib/rules/rules.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
27
|
+
result[reqId] = curBuf;
|
|
27
28
|
});
|
|
28
29
|
res.json(result);
|
|
29
30
|
};
|
package/lib/service/composer.js
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
-
|
|
281
|
-
|
|
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,
|