whistle 2.9.14 → 2.9.16
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/ca/cli.js +95 -0
- package/bin/ca/index.d.ts +1 -0
- package/bin/ca/index.js +43 -0
- package/bin/proxy/cli.js +17 -17
- package/bin/util.js +19 -2
- package/bin/whistle.js +27 -3
- package/biz/webui/cgi-bin/certs/remove.js +1 -1
- package/biz/webui/cgi-bin/composer.js +146 -105
- package/biz/webui/cgi-bin/rootca.js +5 -1
- package/biz/webui/htdocs/img/qrcode-cer.png +0 -0
- package/biz/webui/htdocs/img/qrcode-pem.png +0 -0
- package/biz/webui/htdocs/img/qrcode.png +0 -0
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +44 -43
- package/biz/webui/lib/index.js +35 -1
- package/lib/config.js +9 -9
- package/lib/handlers/file-proxy.js +1 -1
- package/lib/https/ca.js +36 -19
- package/lib/plugins/index.js +9 -1
- package/lib/rules/util.js +14 -4
- package/lib/util/is-utf8.js +1 -1
- package/package.json +1 -1
package/bin/ca/cli.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var net = require('net');
|
|
2
|
+
var fs = require('fs');
|
|
3
|
+
var path = require('path');
|
|
4
|
+
var installRootCA = require('./index');
|
|
5
|
+
var util = require('../util');
|
|
6
|
+
var fileMgr = require('../../lib/util/file-mgr');
|
|
7
|
+
var httpMgr = require('../../lib/util/http-mgr');
|
|
8
|
+
var commonUtil = require('../../lib/util/common');
|
|
9
|
+
var config = require('../../lib/config');
|
|
10
|
+
|
|
11
|
+
var NUM_RE = /^\d+$/;
|
|
12
|
+
var HOST_SUFFIX_RE = /\:(\d+|auto)?$/;
|
|
13
|
+
var HOST_RE = /^[a-z\d_-]+(?:\.[a-z\d_-]+)*$/i;
|
|
14
|
+
var URL_RE = /^https?:\/\/./i;
|
|
15
|
+
var MAX_LEN = 1024 * 1024;
|
|
16
|
+
|
|
17
|
+
function installCert(certFile, url) {
|
|
18
|
+
try {
|
|
19
|
+
installRootCA(fileMgr.convertSlash(certFile));
|
|
20
|
+
util.info('Install root CA (' + (url || certFile) + ') successful.');
|
|
21
|
+
} catch (e) {
|
|
22
|
+
util.error(e.message);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function install(addr) {
|
|
27
|
+
if (addr.file) {
|
|
28
|
+
return installCert(addr.file);
|
|
29
|
+
}
|
|
30
|
+
addr.needRawData = true;
|
|
31
|
+
addr.maxLength = MAX_LEN;
|
|
32
|
+
addr.headers = {
|
|
33
|
+
'user-agent': 'whistle/' + config.name
|
|
34
|
+
};
|
|
35
|
+
httpMgr.request(addr, function(err, body, res) {
|
|
36
|
+
if (err) {
|
|
37
|
+
return util.error(err.message);
|
|
38
|
+
}
|
|
39
|
+
if (res.statusCode != 200) {
|
|
40
|
+
return util.error('Bad response (' + res.statusCode + ').');
|
|
41
|
+
}
|
|
42
|
+
if (!body || !body.length) {
|
|
43
|
+
return util.error('No content.');
|
|
44
|
+
}
|
|
45
|
+
var tempFile = path.join(commonUtil.getWhistlePath(), Date.now() + '-' + util.getHash(addr.url) + '.crt');
|
|
46
|
+
fs.writeFileSync(tempFile, body);
|
|
47
|
+
installCert(tempFile, addr.url);
|
|
48
|
+
fs.unlinkSync(tempFile);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = function(argv) {
|
|
53
|
+
var options = {};
|
|
54
|
+
argv.forEach(function(arg) {
|
|
55
|
+
if (NUM_RE.test(arg)) {
|
|
56
|
+
delete options.addr;
|
|
57
|
+
options.port = parseInt(arg, 10) || options.port;
|
|
58
|
+
} else if (net.isIP(arg)) {
|
|
59
|
+
delete options.addr;
|
|
60
|
+
options.host = arg || options.host;
|
|
61
|
+
} else if (HOST_SUFFIX_RE.test(arg)) {
|
|
62
|
+
delete options.port;
|
|
63
|
+
delete options.addr;
|
|
64
|
+
var port = RegExp.$1;
|
|
65
|
+
if (port > 0) {
|
|
66
|
+
options.port = parseInt(port, 10) || options.port;
|
|
67
|
+
}
|
|
68
|
+
var host = arg.slice(0, - port.length - 1);
|
|
69
|
+
if (host[0] === '[') {
|
|
70
|
+
host = host.substring(1);
|
|
71
|
+
}
|
|
72
|
+
var lastIndex = host.length - 1;
|
|
73
|
+
if (host[lastIndex] === ']') {
|
|
74
|
+
host = host.substring(0, lastIndex);
|
|
75
|
+
}
|
|
76
|
+
if (host && (net.isIP(host) || HOST_RE.test(host))) {
|
|
77
|
+
options.host = host || options.host;
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
delete options.port;
|
|
81
|
+
delete options.host;
|
|
82
|
+
if (URL_RE.test(arg)) {
|
|
83
|
+
options.addr = { url: arg };
|
|
84
|
+
} else {
|
|
85
|
+
options.addr = { file: arg };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (!options.addr) {
|
|
90
|
+
var host = options.host || '127.0.0.1';
|
|
91
|
+
var port = options.port || util.getDefaultPort();
|
|
92
|
+
options.addr = { url: 'http://' + host + ':' + port + '/cgi-bin/rootca' };
|
|
93
|
+
}
|
|
94
|
+
install(options.addr);
|
|
95
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function (certFile: String): void;
|
package/bin/ca/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var spawnSync = require('child_process').spawnSync;
|
|
2
|
+
|
|
3
|
+
function checkSuccess(result) {
|
|
4
|
+
var stderr = result.stderr;
|
|
5
|
+
if (stderr && stderr.length) {
|
|
6
|
+
throw new Error(stderr + '');
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getKeyChain() {
|
|
11
|
+
var result = spawnSync('security', ['default-keychain']);
|
|
12
|
+
checkSuccess(result);
|
|
13
|
+
return (result.stdout + '').split('"')[1];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function installMac(certPath) {
|
|
17
|
+
var result = spawnSync('security', ['add-trusted-cert', '-k', getKeyChain(), certPath]);
|
|
18
|
+
checkSuccess(result);
|
|
19
|
+
var msg = result.stdout + '';
|
|
20
|
+
if (/Error:/i.test(msg)) {
|
|
21
|
+
throw new Error(msg);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
function installWin(certFile) {
|
|
27
|
+
var result = spawnSync('certutil', ['-addstore', '-user', 'Root', certFile]);
|
|
28
|
+
checkSuccess(result);
|
|
29
|
+
if (/ERROR_CANCELLED/i.test(result.stdout + '')) {
|
|
30
|
+
throw new Error('The authorization was canceled by the user.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = function(certFile) {
|
|
35
|
+
var platform = process.platform;
|
|
36
|
+
if (platform === 'darwin') {
|
|
37
|
+
return installMac(certFile);
|
|
38
|
+
}
|
|
39
|
+
if (platform === 'win32') {
|
|
40
|
+
return installWin(certFile);
|
|
41
|
+
}
|
|
42
|
+
throw new Error('Platform ' + platform + ' is unsupported to install root CA for now.');
|
|
43
|
+
};
|
package/bin/proxy/cli.js
CHANGED
|
@@ -2,33 +2,33 @@ var net = require('net');
|
|
|
2
2
|
var proxy = require('./index');
|
|
3
3
|
var util = require('../util');
|
|
4
4
|
|
|
5
|
-
var readConfig = util.readConfig;
|
|
6
5
|
var OFF_RE = /^(?:o|0|-{0,2}off)$/i;
|
|
7
6
|
var BYPASS_RE = /^(?:-{0,2}bypass|-x|-b)$/i;
|
|
8
7
|
var NUM_RE = /^\d+$/;
|
|
9
8
|
var HOST_SUFFIX_RE = /\:(\d+|auto)?$/;
|
|
10
9
|
var HOST_RE = /^[a-z\d_-]+(?:\.[a-z\d_-]+)*$/i;
|
|
11
10
|
|
|
12
|
-
function getDefaultPort() {
|
|
13
|
-
var conf = readConfig();
|
|
14
|
-
conf = conf && conf.options;
|
|
15
|
-
var port = conf && conf.port;
|
|
16
|
-
return port > 0 ? port : 8899;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
function enableProxy(options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
try {
|
|
13
|
+
if (proxy.enableProxy(options)) {
|
|
14
|
+
util.info('Setting global proxy (' + options.host + ':' + options.port + ') successful.');
|
|
15
|
+
} else {
|
|
16
|
+
util.error('Failed to set global proxy (' + options.host + ':' + options.port + ').');
|
|
17
|
+
}
|
|
18
|
+
} catch (e) {
|
|
19
|
+
util.error(e.message);
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
function disableProxy() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
try {
|
|
25
|
+
if (proxy.disableProxy()) {
|
|
26
|
+
util.info('Turn off global proxy successful.');
|
|
27
|
+
} else {
|
|
28
|
+
util.error('Failed to turn off global proxy.');
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
util.error(e.message);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -69,7 +69,7 @@ module.exports = function(argv) {
|
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
71
|
if (!options.port) {
|
|
72
|
-
options.port = getDefaultPort();
|
|
72
|
+
options.port = util.getDefaultPort();
|
|
73
73
|
}
|
|
74
74
|
options.host = options.host || '127.0.0.1';
|
|
75
75
|
enableProxy(options);
|
package/bin/util.js
CHANGED
|
@@ -7,12 +7,13 @@ var config = require('../lib/config');
|
|
|
7
7
|
var colors = require('colors/safe');
|
|
8
8
|
var path = require('path');
|
|
9
9
|
var createHmac = require('crypto').createHmac;
|
|
10
|
+
|
|
10
11
|
/*eslint no-console: "off"*/
|
|
11
12
|
var CHECK_RUNNING_CMD = process.platform === 'win32' ?
|
|
12
13
|
'tasklist /fi "PID eq %s" | findstr /i "node.exe"'
|
|
13
14
|
: 'ps -f -p %s | grep "node"';
|
|
14
15
|
var isWin = process.platform === 'win32';
|
|
15
|
-
|
|
16
|
+
|
|
16
17
|
function isRunning(pid, callback) {
|
|
17
18
|
pid ? cp.exec(util.format(CHECK_RUNNING_CMD, pid),
|
|
18
19
|
function (err, stdout, stderr) {
|
|
@@ -88,6 +89,15 @@ function showUsage(isRunning, options, restart) {
|
|
|
88
89
|
if (parseInt(process.version.slice(1), 10) < 6) {
|
|
89
90
|
warn(colors.bold('\nWarning: The current Node version is too low, access https://nodejs.org to install the latest version, or may not be able to Capture HTTPS CONNECTs\n'));
|
|
90
91
|
}
|
|
92
|
+
var bypass = options.init;
|
|
93
|
+
if (bypass == null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
host: options.host || '127.0.0.1',
|
|
98
|
+
port: port,
|
|
99
|
+
bypass: typeof bypass === 'string' ? bypass : undefined
|
|
100
|
+
};
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
exports.showUsage = showUsage;
|
|
@@ -146,4 +156,11 @@ exports.readConfigList = readConfigList;
|
|
|
146
156
|
exports.getHash = function(str) {
|
|
147
157
|
var hmac = createHmac('sha256', 'a secret');
|
|
148
158
|
return hmac.update(str).digest('hex');
|
|
149
|
-
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
exports.getDefaultPort = function () {
|
|
162
|
+
var conf = readConfig();
|
|
163
|
+
conf = conf && conf.options;
|
|
164
|
+
var port = conf && conf.port;
|
|
165
|
+
return port > 0 ? port : 8899;
|
|
166
|
+
};
|
package/bin/whistle.js
CHANGED
|
@@ -8,14 +8,29 @@ var showStatus = require('./status');
|
|
|
8
8
|
var util = require('./util');
|
|
9
9
|
var plugin = require('./plugin');
|
|
10
10
|
var setProxy = require('./proxy/cli');
|
|
11
|
+
var installCA = require('./ca/cli');
|
|
11
12
|
|
|
12
|
-
var showUsage = util.showUsage;
|
|
13
13
|
var error = util.error;
|
|
14
14
|
var info = util.info;
|
|
15
|
+
var hasInit;
|
|
16
|
+
|
|
17
|
+
function handleEnd(err, options, restart) {
|
|
18
|
+
options = util.showUsage(err, options, restart);
|
|
19
|
+
if (!options || !hasInit) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
var host = options.host + ':' + options.port;
|
|
23
|
+
var argv = [host];
|
|
24
|
+
if (options.bypass) {
|
|
25
|
+
argv.push('-x', options.bypass);
|
|
26
|
+
}
|
|
27
|
+
setProxy(argv);
|
|
28
|
+
installCA([host]);
|
|
29
|
+
}
|
|
15
30
|
|
|
16
31
|
function showStartupInfo(err, options, debugMode, restart) {
|
|
17
32
|
if (!err || err === true) {
|
|
18
|
-
return
|
|
33
|
+
return handleEnd(err, options, restart);
|
|
19
34
|
}
|
|
20
35
|
if (/listen EADDRINUSE/.test(err)) {
|
|
21
36
|
options = util.formatOptions(options);
|
|
@@ -55,7 +70,7 @@ program.setConfig({
|
|
|
55
70
|
showStartupInfo(err, options, true);
|
|
56
71
|
return;
|
|
57
72
|
}
|
|
58
|
-
|
|
73
|
+
handleEnd(false, options);
|
|
59
74
|
console.log('Press [Ctrl+C] to stop ' + config.name + '...');
|
|
60
75
|
},
|
|
61
76
|
startCallback: showStartupInfo,
|
|
@@ -85,6 +100,8 @@ program
|
|
|
85
100
|
.description('Add rules from local js file (.whistle.js by default)');
|
|
86
101
|
program.command('proxy')
|
|
87
102
|
.description('Set global proxy');
|
|
103
|
+
program.command('ca')
|
|
104
|
+
.description('Install root CA');
|
|
88
105
|
program.command('install')
|
|
89
106
|
.description('Install whistle plugin');
|
|
90
107
|
program.command('uninstall')
|
|
@@ -117,6 +134,7 @@ program
|
|
|
117
134
|
.option('-R, --reqCacheSize [reqCacheSize]', 'set the cache size of request data (600 by default)', String, undefined)
|
|
118
135
|
.option('-F, --frameCacheSize [frameCacheSize]', 'set the cache size of webSocket and socket\'s frames (512 by default)', String, undefined)
|
|
119
136
|
.option('-A, --addon [pluginPaths]', 'add custom plugin paths', String, undefined)
|
|
137
|
+
.option('--init [bypass]', 'auto set global proxy (and bypass) and install root CA')
|
|
120
138
|
.option('--config [workers]', 'start the cluster server and set worker number (os.cpus().length by default)', String, undefined)
|
|
121
139
|
.option('--cluster [config]', 'load the startup config from a local file', String, undefined)
|
|
122
140
|
.option('--dnsServer [dnsServer]', 'set custom dns servers', String, undefined)
|
|
@@ -135,6 +153,10 @@ var removeItem = function(list, name) {
|
|
|
135
153
|
var i = list.indexOf(name);
|
|
136
154
|
i !== -1 && list.splice(i, 1);
|
|
137
155
|
};
|
|
156
|
+
if (argv.indexOf('--init') !== -1) {
|
|
157
|
+
hasInit = true;
|
|
158
|
+
process.env.WHISTLE_MODE = (process.env.WHISTLE_MODE || '') + '|persistentCapture';
|
|
159
|
+
}
|
|
138
160
|
if (cmd === 'status') {
|
|
139
161
|
var all = argv[3] === '--all' || argv[3] === '-l';
|
|
140
162
|
if (argv[3] === '-S') {
|
|
@@ -143,6 +165,8 @@ if (cmd === 'status') {
|
|
|
143
165
|
showStatus(all, storage);
|
|
144
166
|
} else if (cmd === 'proxy') {
|
|
145
167
|
setProxy(Array.prototype.slice.call(argv, 3));
|
|
168
|
+
} else if (cmd === 'ca') {
|
|
169
|
+
installCA(Array.prototype.slice.call(argv, 3));
|
|
146
170
|
} else if (/^([a-z]{1,2})?uni(nstall)?$/.test(cmd)) {
|
|
147
171
|
plugin.uninstall(Array.prototype.slice.call(argv, 3));
|
|
148
172
|
} else if (/^([a-z]{1,2})?i(nstall)?$/.test(cmd)) {
|
|
@@ -2,7 +2,7 @@ var ca = require('../../../../lib/https/ca');
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
module.exports = function(req, res) {
|
|
5
|
-
ca.removeCert(req.body
|
|
5
|
+
ca.removeCert(req.body);
|
|
6
6
|
var isparsed = req.query.dataType === 'parsed';
|
|
7
7
|
res.json(isparsed ? ca.getCustomCertsInfo() : ca.getCustomCertsFiles());
|
|
8
8
|
};
|
|
@@ -3,6 +3,7 @@ var gzip = require('zlib').gzip;
|
|
|
3
3
|
var tls = require('tls');
|
|
4
4
|
var crypto = require('crypto');
|
|
5
5
|
var Buffer = require('safe-buffer').Buffer;
|
|
6
|
+
var extend = require('extend');
|
|
6
7
|
var common = require('../../../lib/util/common');
|
|
7
8
|
var config = require('../../../lib/config');
|
|
8
9
|
var util = require('../../../lib/util');
|
|
@@ -16,6 +17,7 @@ var getRawHeaders = hparser.getRawHeaders;
|
|
|
16
17
|
var getRawHeaderNames = hparser.getRawHeaderNames;
|
|
17
18
|
var parseReq = hparser.parse;
|
|
18
19
|
var MAX_LENGTH = 1024 * 512;
|
|
20
|
+
var MAX_REQ_COUNT = 100;
|
|
19
21
|
var TLS_PROTOS = 'https:,wss:,tls:'.split(',');
|
|
20
22
|
var PROXY_OPTS = {
|
|
21
23
|
host: config.host || '127.0.0.1',
|
|
@@ -45,38 +47,53 @@ function drain(socket) {
|
|
|
45
47
|
socket.on('data', util.noop);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
function
|
|
50
|
+
function getReqCount(count) {
|
|
51
|
+
return count > 0 ? Math.min(count, MAX_REQ_COUNT) : 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function handleConnect(options, cb, count) {
|
|
55
|
+
count = getReqCount(count);
|
|
49
56
|
options.headers['x-whistle-policy'] = 'tunnel';
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return cb && cb(err);
|
|
57
|
+
var origOpts = options;
|
|
58
|
+
var lastIndex = count - 1;
|
|
59
|
+
for (var i = 0; i < count; i++) {
|
|
60
|
+
var execCb;
|
|
61
|
+
if (i === lastIndex) {
|
|
62
|
+
execCb = cb;
|
|
63
|
+
} else {
|
|
64
|
+
options = extend({}, origOpts);
|
|
59
65
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
config.connect({
|
|
67
|
+
host: options.hostname,
|
|
68
|
+
port: options.port || 443,
|
|
69
|
+
proxyHost: PROXY_OPTS.host,
|
|
70
|
+
proxyPort: PROXY_OPTS.port,
|
|
71
|
+
headers: options.headers
|
|
72
|
+
}, function(socket, svrRes, err) {
|
|
73
|
+
if (err) {
|
|
74
|
+
return execCb && execCb(err);
|
|
67
75
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
if (!err) {
|
|
77
|
+
if (TLS_PROTOS.indexOf(options.protocol) !== -1) {
|
|
78
|
+
socket = tls.connect({
|
|
79
|
+
rejectUnauthorized: config.rejectUnauthorized,
|
|
80
|
+
socket: socket,
|
|
81
|
+
servername: options.hostname
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
drain(socket);
|
|
85
|
+
var data = options.body;
|
|
86
|
+
if (data && data.length) {
|
|
87
|
+
socket.write(data);
|
|
88
|
+
options.body = data = null;
|
|
89
|
+
}
|
|
73
90
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
79
|
-
}
|
|
91
|
+
execCb && execCb(null, {
|
|
92
|
+
statusCode: svrRes.statusCode,
|
|
93
|
+
headers: svrRes.headers
|
|
94
|
+
});
|
|
95
|
+
}).on('error', execCb || util.noop);
|
|
96
|
+
}
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
function getReqRaw(options) {
|
|
@@ -86,52 +103,64 @@ function getReqRaw(options) {
|
|
|
86
103
|
return raw.join('\r\n') + '\r\n\r\n';
|
|
87
104
|
}
|
|
88
105
|
|
|
89
|
-
function handleWebSocket(options, cb) {
|
|
106
|
+
function handleWebSocket(options, cb, count) {
|
|
107
|
+
count = getReqCount(count);
|
|
90
108
|
if (options.protocol === 'https:' || options.protocol === 'wss:') {
|
|
91
109
|
options.headers[config.HTTPS_FIELD] = 1;
|
|
92
110
|
}
|
|
93
111
|
var binary = !!options.headers['x-whistle-frame-binary'];
|
|
94
112
|
delete options.headers['x-whistle-frame-binary'];
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
113
|
+
var origOpts = options;
|
|
114
|
+
var lastIndex = count - 1;
|
|
115
|
+
for (var i = 0; i < count; i++) {
|
|
116
|
+
var execCb;
|
|
117
|
+
if (i === lastIndex) {
|
|
118
|
+
execCb = cb;
|
|
98
119
|
} else {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
options = extend({}, origOpts);
|
|
121
|
+
}
|
|
122
|
+
util.connect(PROXY_OPTS, function(err, socket) {
|
|
123
|
+
if (err) {
|
|
124
|
+
execCb && execCb(err);
|
|
125
|
+
} else {
|
|
126
|
+
socket.write(getReqRaw(options));
|
|
127
|
+
var data = options.body;
|
|
128
|
+
if ((!data || !data.length) && !cb) {
|
|
129
|
+
return drain(socket);
|
|
108
130
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
sender.send(data, {
|
|
114
|
-
mask: true,
|
|
115
|
-
binary: binary
|
|
116
|
-
}, util.noop);
|
|
117
|
-
options.body = data = null;
|
|
131
|
+
parseReq(socket, function(e) {
|
|
132
|
+
if (e) {
|
|
133
|
+
socket.destroy();
|
|
134
|
+
return execCb && execCb(e);
|
|
118
135
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
136
|
+
var statusCode = socket.statusCode;
|
|
137
|
+
if (statusCode == 101) {
|
|
138
|
+
var sender = getSender(socket);
|
|
139
|
+
if (data) {
|
|
140
|
+
sender.send(data, {
|
|
141
|
+
mask: true,
|
|
142
|
+
binary: binary
|
|
143
|
+
}, util.noop);
|
|
144
|
+
options.body = data = null;
|
|
145
|
+
}
|
|
146
|
+
socket.body = '';
|
|
147
|
+
drain(socket);
|
|
148
|
+
} else {
|
|
149
|
+
socket.destroy();
|
|
150
|
+
}
|
|
151
|
+
execCb && execCb(null, {
|
|
152
|
+
statusCode: statusCode,
|
|
153
|
+
headers: socket.headers || {},
|
|
154
|
+
body: socket.body || ''
|
|
155
|
+
});
|
|
156
|
+
}, true);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
132
160
|
}
|
|
133
161
|
|
|
134
|
-
function handleHttp(options, cb) {
|
|
162
|
+
function handleHttp(options, cb, count) {
|
|
163
|
+
count = getReqCount(count);
|
|
135
164
|
if (options.protocol === 'https:') {
|
|
136
165
|
options.headers[config.HTTPS_FIELD] = 1;
|
|
137
166
|
}
|
|
@@ -139,46 +168,56 @@ function handleHttp(options, cb) {
|
|
|
139
168
|
options.hostname = null;
|
|
140
169
|
options.host = PROXY_OPTS.host;
|
|
141
170
|
options.port = PROXY_OPTS.port;
|
|
142
|
-
var
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
buffer = buffer ? Buffer.concat([buffer, data]) : data;
|
|
149
|
-
if (buffer.length > MAX_LENGTH) {
|
|
150
|
-
buffer = null;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
res.on('end', function() {
|
|
155
|
-
zlib.unzip(res.headers['content-encoding'], buffer, function(err, body) {
|
|
156
|
-
var headers = res.headers;
|
|
157
|
-
if (typeof headers.trailer === 'string' && headers.trailer.indexOf(',') !== -1) {
|
|
158
|
-
headers.trailer = headers.trailer.split(',');
|
|
159
|
-
}
|
|
160
|
-
var result = {
|
|
161
|
-
statusCode: res.statusCode,
|
|
162
|
-
headers: headers,
|
|
163
|
-
trailers: res.trailers,
|
|
164
|
-
rawHeaderNames: getRawHeaderNames(res.rawHeaders),
|
|
165
|
-
rawTrailerNames: getRawHeaderNames(res.rawTrailers)
|
|
166
|
-
};
|
|
167
|
-
if (err) {
|
|
168
|
-
result.body = err.stack;
|
|
169
|
-
} else if (body) {
|
|
170
|
-
result.base64 = body.toString('base64');
|
|
171
|
-
}
|
|
172
|
-
cb(null, result);
|
|
173
|
-
});
|
|
174
|
-
});
|
|
171
|
+
var origOpts = options;
|
|
172
|
+
var lastIndex = count - 1;
|
|
173
|
+
for (var i = 0; i < count; i++) {
|
|
174
|
+
var execCb;
|
|
175
|
+
if (i === lastIndex) {
|
|
176
|
+
execCb = cb;
|
|
175
177
|
} else {
|
|
176
|
-
|
|
178
|
+
options = extend({}, origOpts);
|
|
177
179
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
var client = http.request(options, function(res) {
|
|
181
|
+
if (execCb) {
|
|
182
|
+
res.on('error', execCb);
|
|
183
|
+
var buffer;
|
|
184
|
+
res.on('data', function(data) {
|
|
185
|
+
if (buffer !== null) {
|
|
186
|
+
buffer = buffer ? Buffer.concat([buffer, data]) : data;
|
|
187
|
+
if (buffer.length > MAX_LENGTH) {
|
|
188
|
+
buffer = null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
res.on('end', function() {
|
|
193
|
+
zlib.unzip(res.headers['content-encoding'], buffer, function(err, body) {
|
|
194
|
+
var headers = res.headers;
|
|
195
|
+
if (typeof headers.trailer === 'string' && headers.trailer.indexOf(',') !== -1) {
|
|
196
|
+
headers.trailer = headers.trailer.split(',');
|
|
197
|
+
}
|
|
198
|
+
var result = {
|
|
199
|
+
statusCode: res.statusCode,
|
|
200
|
+
headers: headers,
|
|
201
|
+
trailers: res.trailers,
|
|
202
|
+
rawHeaderNames: getRawHeaderNames(res.rawHeaders),
|
|
203
|
+
rawTrailerNames: getRawHeaderNames(res.rawTrailers)
|
|
204
|
+
};
|
|
205
|
+
if (err) {
|
|
206
|
+
result.body = err.stack;
|
|
207
|
+
} else if (body) {
|
|
208
|
+
result.base64 = body.toString('base64');
|
|
209
|
+
}
|
|
210
|
+
execCb(null, result);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
drain(res);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
client.on('error', execCb || util.noop);
|
|
218
|
+
client.end(options.body);
|
|
219
|
+
options.body = null;
|
|
220
|
+
}
|
|
182
221
|
}
|
|
183
222
|
|
|
184
223
|
function getCharset(headers) {
|
|
@@ -296,13 +335,15 @@ module.exports = function(req, res) {
|
|
|
296
335
|
if (err) {
|
|
297
336
|
return handleResponse && handleResponse(err);
|
|
298
337
|
}
|
|
338
|
+
var count = req.body.repeatCount;
|
|
339
|
+
count = count > 0 ? count : req.body.repeatTimes;
|
|
299
340
|
if (isWs) {
|
|
300
341
|
options.method = 'GET';
|
|
301
|
-
handleWebSocket(options, handleResponse);
|
|
342
|
+
handleWebSocket(options, handleResponse, count);
|
|
302
343
|
} else if (isConn) {
|
|
303
|
-
handleConnect(options, handleResponse);
|
|
344
|
+
handleConnect(options, handleResponse, count);
|
|
304
345
|
} else {
|
|
305
|
-
handleHttp(options, handleResponse);
|
|
346
|
+
handleHttp(options, handleResponse, count);
|
|
306
347
|
}
|
|
307
348
|
if (!handleResponse) {
|
|
308
349
|
res.json({ec: 0, em: 'success'});
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
var getRootCAFile = require('../../../lib/https/ca').getRootCAFile;
|
|
2
2
|
|
|
3
3
|
module.exports = function(req, res) {
|
|
4
|
-
|
|
4
|
+
var type = req.query.type;
|
|
5
|
+
if (type !== 'cer' && type !== 'pem') {
|
|
6
|
+
type = 'crt';
|
|
7
|
+
}
|
|
8
|
+
res.download(getRootCAFile(), 'rootCA.' + type);
|
|
5
9
|
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|