whistle 2.10.5 → 2.10.6

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.
@@ -1015,8 +1015,10 @@ function toHttp1(req, res) {
1015
1015
  var handleAbort = function () {
1016
1016
  if (client) {
1017
1017
  client.abort();
1018
- res.destroy();
1019
1018
  client = null;
1019
+ if (!res.writableEnded && !res.finished) {
1020
+ res.destroy();
1021
+ }
1020
1022
  }
1021
1023
  };
1022
1024
  addReqInfo(req);
@@ -19,7 +19,7 @@ function getZipType(options) {
19
19
  }
20
20
 
21
21
  function unzipBody(options, body, callback) {
22
- return zlib.unzip(getZipType(options), body, callback);
22
+ return zlib.unzip(getZipType(options), util.formatBuffer(body), callback);
23
23
  }
24
24
 
25
25
  function checkType(res) {
@@ -244,7 +244,8 @@ function emitDataEvents(req, res, proxy) {
244
244
  var captureReqStream;
245
245
  var maxReqSize;
246
246
  var reqInfo;
247
- var setReqBody = function (body, end) {
247
+ var setReqBody = function (end) {
248
+ reqBody = util.formatBuffer(reqBody);
248
249
  if (captureReqStream && cseSep) {
249
250
  reqBody = parseFrame(reqBody, false, end);
250
251
  } else {
@@ -257,7 +258,7 @@ function emitDataEvents(req, res, proxy) {
257
258
  maxReqSize = useBigData ? BIG_DATA_SIZE : (captureReqStream ? MAX_REQ_BODY_SIZE : MAX_SIZE);
258
259
  if (captureReqStream) {
259
260
  data.isCse = !!cseSep;
260
- reqBody && !reqData.body && setReqBody(reqBody);
261
+ reqBody && !reqData.body && setReqBody();
261
262
  }
262
263
  }
263
264
  };
@@ -277,32 +278,33 @@ function emitDataEvents(req, res, proxy) {
277
278
  var end = stream.end;
278
279
  stream.write = function (chunk) {
279
280
  if (chunk) {
281
+ reqData.size += chunk.length;
280
282
  if (reqBody || reqBody === null) {
281
283
  if (useFrames) {
282
284
  reqBody = '';
283
285
  } else {
284
- reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
286
+ reqBody = util.joinBuffer(reqBody, chunk);
285
287
  if (captureReqStream) {
286
- setReqBody(reqBody);
287
- }
288
- if (reqBody.length > maxReqSize) {
288
+ setReqBody();
289
+ if (reqBody && reqBody.length > maxReqSize) {
290
+ reqBody = false;
291
+ }
292
+ } else if (reqData.size > maxReqSize) {
289
293
  reqBody = false;
290
294
  }
291
295
  }
292
296
  }
293
- reqData.size += chunk.length;
294
297
  }
295
298
  updateEvent && proxy.emit(updateEvent, req.fullUrl, false);
296
299
  return write.apply(this, arguments);
297
300
  };
298
301
  stream.end = function (chunk) {
299
- if (chunk) {
300
- reqData.size += chunk.length;
301
- reqBody = reqBody ? Buffer.concat([reqBody, chunk]) : chunk;
302
- }
303
302
  requestTime = Date.now();
304
303
  if (useFrames) {
305
304
  reqBody = '';
305
+ } else if (chunk) {
306
+ reqData.size += chunk.length;
307
+ reqBody = util.joinBuffer(reqBody, chunk);
306
308
  }
307
309
  unzipBody(reqInfo, reqBody, function (err, body) {
308
310
  setRequestTime(requestTime);
@@ -310,7 +312,7 @@ function emitDataEvents(req, res, proxy) {
310
312
  data.endTime = endTime;
311
313
  }
312
314
  reqBody = err ? util.getErrorStack(err) : body;
313
- setReqBody(reqBody, true);
315
+ setReqBody(true);
314
316
  !data.isCse && setUnzipSize(body, reqData);
315
317
  checkBodySize(reqData, useBigData);
316
318
  });
@@ -339,6 +341,14 @@ function emitDataEvents(req, res, proxy) {
339
341
  }
340
342
  }
341
343
  var maxResSize = useBigData ? BIG_DATA_SIZE : (captureStream ? MAX_RES_BODY_SIZE : MAX_SIZE);
344
+ var setResBody = function (end) {
345
+ resBody = util.formatBuffer(resBody);
346
+ if (isSse) {
347
+ resBody = parseFrame(resBody, true, end);
348
+ } else {
349
+ resData.body = resBody;
350
+ }
351
+ };
342
352
  data.isSse = isSse;
343
353
  captureStream && updateReqInfo();
344
354
  if (!cleared && util.hasBody(info, req) && checkType(info)) {
@@ -353,46 +363,39 @@ function emitDataEvents(req, res, proxy) {
353
363
  var end = stream.end;
354
364
  stream.write = function (chunk) {
355
365
  if (chunk) {
366
+ resData.size += chunk.length;
356
367
  if (resBody || resBody === null) {
357
368
  if (useFrames) {
358
369
  resBody = '';
359
370
  } else {
360
- resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
371
+ resBody = util.joinBuffer(resBody, chunk);
361
372
  if (captureStream) {
362
- if (isSse) {
363
- resBody = parseFrame(resBody, true);
364
- } else {
365
- resData.body = resBody;
373
+ setResBody();
374
+ if (resBody && resBody.length > maxResSize) {
375
+ resBody = false;
366
376
  }
367
- }
368
- if (resBody && resBody.length > maxResSize) {
377
+ } else if (resData.size > maxResSize) {
369
378
  resBody = false;
370
379
  }
371
380
  }
372
381
  }
373
- resData.size += chunk.length;
374
382
  }
375
383
  updateEvent && proxy.emit(updateEvent, req.fullUrl, true);
376
384
  return write.apply(this, arguments);
377
385
  };
378
386
  stream.end = function (chunk) {
379
- if (chunk) {
380
- resData.size += chunk.length;
381
- resBody = resBody ? Buffer.concat([resBody, chunk]) : chunk;
382
- }
383
387
  endTime = Date.now();
384
388
  delete data.abort;
385
389
  if (useFrames) {
386
390
  resBody = '';
391
+ } else if (chunk) {
392
+ resData.size += chunk.length;
393
+ resBody = util.joinBuffer(resBody, chunk);
387
394
  }
388
395
  resData.hasGzipError = unzipBody(info, resBody, function (err, body) {
389
396
  if (!data.resError) {
390
397
  resBody = err ? util.getErrorStack(err) : body;
391
- if (isSse) {
392
- resBody = parseFrame(resBody, true, true);
393
- } else {
394
- resData.body = resBody;
395
- }
398
+ setResBody(true);
396
399
  }
397
400
  !isSse && setUnzipSize(body, resData);
398
401
  checkBodySize(resData, useBigData);
@@ -159,6 +159,7 @@ function handleParams(req, params, urlParams, enableBigData) {
159
159
  var delProps = util.parseDelReqBody(req);
160
160
  var hasBody;
161
161
  var buffer;
162
+ var len = 0;
162
163
  if (params || delProps) {
163
164
  var maxReqSize = enableBigData || util.isEnable(req, 'reqMergeBigData') ? BIG_MAX_REQ_SIZE : MAX_REQ_SIZE;
164
165
  var transform;
@@ -171,15 +172,18 @@ function handleParams(req, params, urlParams, enableBigData) {
171
172
  transform._transform = function (chunk, _, callback) {
172
173
  if (chunk) {
173
174
  if (!interrupt) {
174
- buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
175
+ len += chunk.length;
176
+ buffer = buffer || [];
177
+ buffer.push(chunk);
175
178
  chunk = null;
176
- if (buffer.length > maxReqSize) {
179
+ if (len > maxReqSize) {
177
180
  interrupt = true;
178
- chunk = buffer;
181
+ chunk = Buffer.concat(buffer, len);
179
182
  buffer = null;
180
183
  }
181
184
  }
182
185
  } else if (buffer && buffer.length) {
186
+ buffer = util.formatBuffer(buffer, len);
183
187
  var body;
184
188
  var isGBK = !util.isUtf8(buffer);
185
189
  if (isGBK) {
@@ -388,7 +392,7 @@ function handleParams(req, params, urlParams, enableBigData) {
388
392
  lastChunk = !chunk;
389
393
  if (chunk && preBuffer !== null) {
390
394
  preBuffer = preBuffer ? Buffer.concat([preBuffer, chunk]) : chunk;
391
- if (!preBuffer || preBuffer.length <= length) {
395
+ if (preBuffer.length <= length) {
392
396
  return callback(null, lastChunk ? preBuffer : null);
393
397
  }
394
398
  if (!util.startWithList(preBuffer, startBoundary)) {
@@ -89,10 +89,10 @@ function showDnsError(res, err) {
89
89
  function setCookies(headers, data) {
90
90
  var newCookies = data.headers['set-cookie'];
91
91
  if (!Array.isArray(newCookies)) {
92
- if (!newCookies || typeof newCookies !== 'string') {
92
+ if (!util.isString(newCookies)) {
93
93
  return;
94
94
  }
95
- newCookies = newCookies.split(',');
95
+ newCookies = [newCookies];
96
96
  }
97
97
  if (newCookies.length) {
98
98
  var cookies = headers['set-cookie'];
@@ -105,12 +105,12 @@ function setCookies(headers, data) {
105
105
  var newNameMap = {};
106
106
  newCookies.forEach(function (cookie) {
107
107
  var index = cookie.indexOf('=');
108
- var name = index == -1 ? name : cookie.substring(0, index);
108
+ var name = index == -1 ? cookie : cookie.substring(0, index);
109
109
  newNameMap[name] = 1;
110
110
  });
111
111
  cookies.forEach(function (cookie) {
112
112
  var index = cookie.indexOf('=');
113
- var name = index == -1 ? name : cookie.substring(0, index);
113
+ var name = index == -1 ? cookie : cookie.substring(0, index);
114
114
  if (!newNameMap[name]) {
115
115
  newCookies.push(cookie);
116
116
  }
@@ -333,7 +333,7 @@ var pushFrame = function (reqId, data, opts, isClient) {
333
333
  addFrame(opts);
334
334
  };
335
335
  var addParserApi = function (req, conn, state, reqId) {
336
- state = state.split(',').forEach(function (name) {
336
+ state.split(',').forEach(function (name) {
337
337
  initState(req, name);
338
338
  });
339
339
  req.on('clientFrame', function (data, opts) {
@@ -542,7 +542,7 @@ var getOptions = function (opts, binary, toServer) {
542
542
  var base64ToBuffer = function (base64) {
543
543
  if (base64) {
544
544
  try {
545
- return new Buffer(base64, 'base64');
545
+ return Buffer.from(base64, 'base64');
546
546
  } catch (e) {}
547
547
  }
548
548
  };
@@ -165,7 +165,7 @@ function getTempFiles(list, cb) {
165
165
  cb(result);
166
166
  }
167
167
  };
168
- list = list.forEach(function(filename) {
168
+ list.forEach(function(filename) {
169
169
  filename = common.getTempFile(filename);
170
170
  if (!filename) {
171
171
  return execCb();
@@ -504,7 +504,7 @@ function sessionsHandler() {
504
504
  common.sendGzip(req, res, data);
505
505
  });
506
506
  } catch (e) {
507
- common.sendRes(req, 500, e.stack);
507
+ common.sendRes(res, 500, e.stack);
508
508
  }
509
509
  }
510
510
  );
@@ -697,9 +697,9 @@ function isUrlEncoded(req) {
697
697
  exports.isUrlEncoded = isUrlEncoded;
698
698
 
699
699
  function readStream(stream, callback) {
700
- var buffer = null;
700
+ var buffer = [];
701
701
  stream.on('data', function(chunk) {
702
- buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
702
+ buffer.push(chunk);
703
703
  });
704
704
  stream.once('end', function() {
705
705
  var buf;
@@ -708,6 +708,7 @@ function readStream(stream, callback) {
708
708
  var err;
709
709
  var jsonErr;
710
710
  stream.zlib = zlibx;
711
+ buffer = buffer.length > 1 ? Buffer.concat(buffer) : (buffer[0] || null);
711
712
  var encoding = stream.headers && stream.headers['content-encoding'];
712
713
  var getBuffer = function(cb) {
713
714
  if (err || buf !== undefined) {
@@ -36,21 +36,24 @@ function readSingleFile(path, callback) {
36
36
  return callback();
37
37
  }
38
38
  var stream = fs.createReadStream(convertSlash(path));
39
- var done, buf;
39
+ var done;
40
+ var buf = [];
41
+ var len = 0;
40
42
  var execCallback = function (err) {
41
43
  if (done) {
42
44
  return;
43
45
  }
44
46
  done = true;
45
47
  stream.close();
46
- callback(err ? null : buf);
48
+ callback(buf.length > 1 ? Buffer.concat(buf) : buf[0]);
47
49
  };
48
50
  stream.on('data', function (data) {
49
51
  if (done) {
50
52
  return;
51
53
  }
52
- buf = buf ? Buffer.concat([buf, data]) : data;
53
- if (buf.length > MAX_SIZE) {
54
+ len += data.length;
55
+ buf.push(data);
56
+ if (len > MAX_SIZE) {
54
57
  execCallback();
55
58
  }
56
59
  });
@@ -182,6 +182,10 @@ function gunzip(err, res, body, callback) {
182
182
  }
183
183
  }
184
184
 
185
+ function getBody(body, len) {
186
+ return body.length > 1 ? Buffer.concat(body, len) : (body[0] || '');
187
+ }
188
+
185
189
  function request(options, callback) {
186
190
  loadPlugin(options, function (err) {
187
191
  if (err) {
@@ -230,21 +234,23 @@ function request(options, callback) {
230
234
  return callback(null, res, res);
231
235
  }
232
236
  addTimeout();
233
- var body = '';
237
+ var body = [];
238
+ var len = 0;
234
239
  res.on('data', function (data) {
235
- body = body ? Buffer.concat([body, data]) : data;
240
+ len += data.length;
241
+ body.push(data);
236
242
  addTimeout();
237
- if (maxLength && body.length > maxLength) {
243
+ if (maxLength && len > maxLength) {
238
244
  var err;
239
245
  if (!options.ignoreExceedError) {
240
246
  err = new Error('The response body exceeded length limit');
241
247
  err.code = EXCEED;
242
248
  }
243
- handleCallback(err, res, body);
249
+ handleCallback(err, res, getBody(body, len));
244
250
  }
245
251
  });
246
252
  res.on('end', function() {
247
- handleCallback(null, res, body);
253
+ handleCallback(null, res, getBody(body, len));
248
254
  });
249
255
  };
250
256
  client = sendReq(options, function (err, res) {
@@ -293,7 +299,8 @@ function readFile(url, callback) {
293
299
 
294
300
  var stream = fs.createReadStream(filePath, OPTIONS);
295
301
  var done;
296
- var body = '';
302
+ var body = [];
303
+ var len = 0;
297
304
  var listener = function (err) {
298
305
  if (done) {
299
306
  return;
@@ -305,14 +312,15 @@ function readFile(url, callback) {
305
312
  done = true;
306
313
  data.mtime = time;
307
314
  stream.close();
308
- triggerChange(data, body);
315
+ triggerChange(data, body.join(''));
309
316
  };
310
317
  stream.on('data', function (text) {
311
318
  if (done) {
312
319
  return;
313
320
  }
314
- body += text;
315
- if (body.length > MAX_FILE_LEN) {
321
+ len += text.length;
322
+ body.push(text);
323
+ if (len > MAX_FILE_LEN) {
316
324
  listener();
317
325
  }
318
326
  });
package/lib/util/index.js CHANGED
@@ -747,24 +747,38 @@ exports.disableCSP = disableCSP;
747
747
 
748
748
  var interfaces = os.networkInterfaces();
749
749
  var hostname = os.hostname();
750
+ var serverInfo;
750
751
  var simpleHostname = '';
751
752
  var cpus = os.cpus();
752
753
  var addressList = [];
753
754
  var usiTimer;
754
755
 
755
- function updateSystyemInfo() {
756
+ function updateServerInfo() {
757
+ serverInfo = {ipv4: [], ipv6: []};
758
+ Object.keys(interfaces).forEach(function(ifname) {
759
+ interfaces[ifname].forEach(function (iface) {
760
+ if (iface.internal) {
761
+ return;
762
+ }
763
+ serverInfo[iface.family == 'IPv4' || iface.family === 4 ? 'ipv4' : 'ipv6'].push(iface.address);
764
+ });
765
+ });
766
+ }
767
+
768
+ function updateSysInfo() {
756
769
  clearTimeout(usiTimer);
757
770
  interfaces = os.networkInterfaces();
771
+ updateServerInfo();
758
772
  hostname = os.hostname();
759
773
  addressList = [];
760
774
  common.walkInterfaces(function (info) {
761
775
  addressList.push(info.address.toLowerCase());
762
776
  });
763
- usiTimer = setTimeout(updateSystyemInfo, 36000);
777
+ usiTimer = setTimeout(updateSysInfo, 36000);
764
778
  }
765
779
 
766
- updateSystyemInfo();
767
- process.on('w2NetworkInterfacesChange', updateSystyemInfo);
780
+ updateSysInfo();
781
+ process.on('w2NetworkInterfacesChange', updateSysInfo);
768
782
 
769
783
  if (isString(hostname)) {
770
784
  simpleHostname = hostname.replace(/[^\w.-]+/g, '').substring(0, 20);
@@ -874,15 +888,13 @@ exports.removeClientId = function (headers) {
874
888
  delete headers[config.CLIENT_ID_HEADER];
875
889
  };
876
890
 
877
- function networkInterfaces() {
878
- return interfaces;
879
- }
880
-
881
891
  function getHostname() {
882
892
  return hostname;
883
893
  }
884
894
 
885
- exports.networkInterfaces = networkInterfaces;
895
+ exports.getServerInfo = function() {
896
+ return serverInfo;
897
+ };
886
898
  exports.hostname = getHostname;
887
899
 
888
900
  function getProxyTunnelPath(req, isHttps) {
@@ -1613,35 +1625,35 @@ function getPipeIconvStream(headers) {
1613
1625
  pipeStream.addTail(iconv.encodeStream(charset));
1614
1626
  } else {
1615
1627
  pipeStream.addHead(function (res, next) {
1616
- var buffer, iconvDecoder;
1617
-
1618
- res.on('data', function (chunk) {
1619
- buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
1620
- resolveCharset(buffer);
1621
- });
1622
- res.on('end', resolveCharset);
1623
-
1624
- function resolveCharset(chunk) {
1625
- if (!charset) {
1626
- if (chunk && buffer.length < 25600) {
1628
+ var buf = [];
1629
+ var len = 0;
1630
+ var resolveCharset = function(chunk) {
1631
+ if (chunk) {
1632
+ len += chunk.length;
1633
+ buf.push(chunk);
1634
+ if (len < 25600) {
1627
1635
  return;
1628
1636
  }
1629
- charset = !buffer || isUtf8(buffer) ? 'utf8' : 'GB18030';
1630
- }
1631
- if (!iconvDecoder) {
1632
- iconvDecoder = iconv.decodeStream(charset);
1633
- next(iconvDecoder);
1634
1637
  }
1635
- if (buffer) {
1636
- iconvDecoder.write(buffer);
1637
- buffer = null;
1638
+ res.removeListener('data', resolveCharset);
1639
+ res.removeListener('end', resolveCharset);
1640
+ buf = buf.length > 1 ? Buffer.concat(buf, len) : buf[0];
1641
+ if (!buf) {
1642
+ return next(res);
1638
1643
  }
1639
- !chunk && iconvDecoder.end();
1640
- }
1644
+ charset = isUtf8(buf) ? 'utf8' : 'GB18030';
1645
+ var decoder = iconv.decodeStream(charset);
1646
+ decoder.write(buf);
1647
+ next(res.pipe(decoder));
1648
+ buf = null;
1649
+ };
1650
+
1651
+ res.on('data', resolveCharset);
1652
+ res.on('end', resolveCharset);
1641
1653
  });
1642
1654
 
1643
1655
  pipeStream.addTail(function (src, next) {
1644
- next(src.pipe(iconv.encodeStream(charset)));
1656
+ next(charset ? src.pipe(iconv.encodeStream(charset)) : src);
1645
1657
  });
1646
1658
  }
1647
1659
 
@@ -3357,7 +3369,7 @@ exports.parseRange = function (req, size) {
3357
3369
  }
3358
3370
  var start = size;
3359
3371
  var end = -1;
3360
- range = range.split(',').forEach(function (item) {
3372
+ range.split(',').forEach(function (item) {
3361
3373
  item = item.split('-');
3362
3374
  var s = parseInt(item[0], 10);
3363
3375
  var e = parseInt(item[1], 10);
@@ -4016,3 +4028,18 @@ exports.getFrameId = function() {
4016
4028
  }
4017
4029
  return Date.now() + '-00' + frameIndex;
4018
4030
  };
4031
+
4032
+ exports.joinBuffer = function(buf, chunk) {
4033
+ if (!buf) {
4034
+ return chunk;
4035
+ }
4036
+ if (!Array.isArray(buf)) {
4037
+ return [buf, chunk];
4038
+ }
4039
+ buf.push(chunk);
4040
+ return buf;
4041
+ };
4042
+
4043
+ exports.formatBuffer = function(buf, len) {
4044
+ return Array.isArray(buf) ? Buffer.concat(buf, len) : buf;
4045
+ };
@@ -5,19 +5,21 @@ var URL_RE = /^([a-z0-9.+-]+:)\/\/([^/?#]*)(\/[^?#]*)?(\?[^#]*)?(#[\s\S]*)?$/i;
5
5
  var HOST_RE = /^(.+)(?::(\d*))$/;
6
6
 
7
7
  module.exports = function (url) {
8
- if (!URL_RE.test(url)) {
8
+ var urlMatch = URL_RE.exec(url);
9
+ if (!urlMatch) {
9
10
  return parseUrl(url);
10
11
  }
11
- var protocol = RegExp.$1;
12
- var host = RegExp.$2;
13
- var pathname = RegExp.$3 || '/';
14
- var search = RegExp.$4;
15
- var hash = RegExp.$5 || null;
12
+ var protocol = urlMatch[1];
13
+ var host = urlMatch[2];
14
+ var pathname = urlMatch[3] || '/';
15
+ var search = urlMatch[4] || '';
16
+ var hash = urlMatch[5] || null;
16
17
  var port = null;
17
18
  var hostname = host;
18
- if (HOST_RE.test(host)) {
19
- hostname = RegExp.$1;
20
- port = RegExp.$2;
19
+ var hostMatch = HOST_RE.exec(host);
20
+ if (hostMatch) {
21
+ hostname = hostMatch[1];
22
+ port = hostMatch[2];
21
23
  }
22
24
 
23
25
  return {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "whistle",
3
3
  "description": "HTTP, HTTP2, HTTPS, Websocket debugging proxy",
4
- "version": "2.10.5",
4
+ "version": "2.10.6",
5
5
  "dataDirname": ".whistle",
6
6
  "localUIHost": "local.whistlejs.com",
7
7
  "port": 8899,