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.
- package/assets/js/log.js +4 -0
- package/bin/api.js +3 -1
- package/bin/util.js +1 -1
- 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/cgi-bin/util.js +1 -1
- package/biz/webui/cgi-bin/values/add.js +15 -13
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +50 -51
- package/biz/webui/lib/index.js +39 -30
- package/index.js +10 -12
- package/lib/config.js +25 -79
- package/lib/handlers/file-proxy.js +1 -1
- package/lib/https/ca.js +18 -17
- package/lib/https/h2.js +54 -35
- package/lib/https/index.js +124 -107
- package/lib/inspectors/data.js +9 -3
- package/lib/inspectors/log.js +14 -33
- package/lib/inspectors/req.js +3 -6
- package/lib/inspectors/res.js +2 -5
- package/lib/inspectors/rules.js +11 -6
- package/lib/inspectors/weinre.js +1 -1
- package/lib/plugins/index.js +45 -54
- package/lib/plugins/load-plugin.js +31 -40
- package/lib/rules/dns.js +1 -1
- package/lib/rules/index.js +3 -1
- package/lib/rules/protocols.js +2 -4
- package/lib/rules/rules.js +3 -5
- package/lib/rules/util.js +2 -7
- package/lib/service/compose-data.js +2 -1
- package/lib/service/composer.js +12 -10
- package/lib/service/service.js +3 -5
- package/lib/socket-mgr.js +5 -2
- package/lib/tunnel.js +9 -5
- package/lib/util/common.js +190 -37
- package/lib/util/data-server.js +5 -1
- package/lib/util/drain.js +5 -6
- package/lib/util/file-mgr.js +1 -1
- package/lib/util/http-mgr.js +6 -2
- package/lib/util/index.js +48 -69
- package/lib/util/speed-transform.js +2 -2
- package/lib/util/transproto.js +4 -3
- package/lib/util/whistle-transform.js +2 -2
- package/lib/util/zlib.js +1 -1
- package/package.json +4 -4
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) {
|
|
@@ -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
|
-
|
|
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
|
-
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
if (isEnable('forHttp') || disable.captureHttps) {
|
|
1216
1225
|
return next(chunk);
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
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
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
)
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
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
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
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.
|
|
1252
|
-
socket._w2TunnelKey =
|
|
1253
|
-
tunnelTmplData.set(
|
|
1254
|
-
|
|
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
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
+
};
|
|
1265
|
+
var useNoSNIServer = function () {
|
|
1266
|
+
serverKey = requestCert ? ':' + domain : domain;
|
|
1267
|
+
serverAgent.createServer(serverKey, handlers, handleConnect, 0, 0);
|
|
1268
|
+
};
|
|
1264
1269
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
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
|
-
|
|
1278
|
+
getSNIServer(h2Handlers, handleConnect, disableH2, requestCert);
|
|
1279
|
+
} else if (isHttpH2) {
|
|
1280
|
+
getHttp2Server(h2Handlers, handleConnect);
|
|
1281
|
+
} else {
|
|
1282
|
+
useNoSNIServer();
|
|
1282
1283
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1308
|
+
return next(chunk);
|
|
1309
|
+
}
|
|
1310
|
+
var requestCert =
|
|
1293
1311
|
(enable.clientCert || enable.requestCert) &&
|
|
1294
1312
|
!disable.clientCert &&
|
|
1295
1313
|
!disable.requestCert;
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
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
|
);
|
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) {
|
|
@@ -419,7 +421,7 @@ function emitDataEvents(req, res, proxy) {
|
|
|
419
421
|
}
|
|
420
422
|
|
|
421
423
|
req.once('dest', function (_req) {
|
|
422
|
-
|
|
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
|
-
|
|
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
|
|
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') {
|
package/lib/inspectors/log.js
CHANGED
|
@@ -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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
}
|
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
|
@@ -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.
|
|
1243
|
+
util.onReadEnd(_res, function () {
|
|
1247
1244
|
var trailers = _res.trailers;
|
|
1248
1245
|
if (
|
|
1249
1246
|
!res.chunkedEncoding ||
|
package/lib/inspectors/rules.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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);
|
package/lib/inspectors/weinre.js
CHANGED
|
@@ -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.
|
|
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) {
|
package/lib/plugins/index.js
CHANGED
|
@@ -289,8 +289,8 @@ pluginMgr.on('uninstall', function (result) {
|
|
|
289
289
|
});
|
|
290
290
|
});
|
|
291
291
|
|
|
292
|
-
function
|
|
293
|
-
return '[' + (new Date(
|
|
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 =
|
|
1182
|
+
pipe = resolvePipe(req, hRules, rulesMgr);
|
|
1179
1183
|
} else {
|
|
1180
|
-
pipe =
|
|
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
|
|
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
|
|
1240
|
+
var handleConnect = function (socket) {
|
|
1238
1241
|
if (!done) {
|
|
1239
1242
|
done = true;
|
|
1240
|
-
if (req
|
|
1241
|
-
return
|
|
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
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
client
|
|
1250
|
-
client
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
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
|
}
|