whistle 2.9.15 → 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/biz/webui/cgi-bin/composer.js +146 -105
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +11 -10
- package/biz/webui/lib/index.js +28 -0
- package/lib/handlers/file-proxy.js +1 -1
- package/lib/plugins/index.js +9 -1
- package/lib/rules/util.js +5 -1
- package/package.json +1 -1
|
@@ -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'});
|