whistle 2.10.5 → 2.10.7
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/menu.html +2 -2
- package/assets/modal.html +2 -2
- package/assets/tab.html +2 -2
- package/bin/api.js +545 -0
- package/bin/import.js +3 -3
- package/bin/plugin.js +4 -8
- package/bin/use.js +22 -8
- package/bin/util.js +12 -7
- package/bin/whistle.js +11 -1
- package/biz/webui/cgi-bin/abort.js +14 -5
- package/biz/webui/cgi-bin/frames.js +12 -0
- package/biz/webui/cgi-bin/get-session.js +7 -3
- package/biz/webui/cgi-bin/is-enabled-https.js +6 -0
- package/biz/webui/cgi-bin/plugins/disable-plugin.js +16 -7
- package/biz/webui/cgi-bin/plugins/list.js +17 -0
- package/biz/webui/cgi-bin/plugins/plugin.js +21 -0
- package/biz/webui/cgi-bin/plugins/status.js +21 -0
- package/biz/webui/cgi-bin/rules/is-multi-select.js +7 -0
- package/biz/webui/cgi-bin/rules/move-top.js +11 -0
- package/biz/webui/cgi-bin/rules/select.js +1 -1
- package/biz/webui/cgi-bin/rules/select2.js +16 -0
- package/biz/webui/cgi-bin/rules/status.js +6 -0
- package/biz/webui/cgi-bin/rules/unselect.js +3 -2
- package/biz/webui/cgi-bin/rules/unselect2.js +18 -0
- package/biz/webui/cgi-bin/rules/value.js +19 -0
- package/biz/webui/cgi-bin/sessions.js +6 -0
- package/biz/webui/cgi-bin/util.js +45 -20
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +51 -51
- package/biz/webui/lib/index.js +1 -3
- package/lib/https/index.js +7 -5
- package/lib/init.js +1 -0
- package/lib/inspectors/data.js +39 -34
- package/lib/inspectors/req.js +9 -6
- package/lib/inspectors/res.js +10 -14
- package/lib/plugins/index.js +2 -2
- package/lib/plugins/load-plugin.js +19 -8
- package/lib/rules/util.js +20 -10
- package/lib/service/composer.js +7 -22
- package/lib/service/data-center.js +0 -12
- package/lib/service/generate-saz.js +2 -2
- package/lib/service/service.js +8 -7
- package/lib/service/util.js +6 -16
- package/lib/socket-mgr.js +23 -17
- package/lib/tunnel.js +7 -17
- package/lib/upgrade.js +4 -8
- package/lib/util/common.js +78 -11
- package/lib/util/data-server.js +273 -0
- package/lib/util/file-mgr.js +7 -4
- package/lib/util/http-mgr.js +17 -9
- package/lib/util/index.js +67 -54
- package/lib/util/parse-url.js +11 -9
- package/lib/util/patch.js +2 -6
- package/lib/util/speed-transform.js +17 -6
- package/lib/util/whistle-transform.js +18 -7
- package/package.json +10 -7
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
var common = require('../util/common');
|
|
2
2
|
var request = require('../util/http-mgr').request;
|
|
3
3
|
var util = require('./util');
|
|
4
|
-
var extend = require('extend');
|
|
5
4
|
|
|
6
5
|
var requestData;
|
|
7
6
|
var BASE_URL = 'https://' + common.SERVICE_HOST;
|
|
@@ -71,17 +70,6 @@ var saveComposeData = function(data) {
|
|
|
71
70
|
if (!config.whistleToken || !Array.isArray(historyList)) {
|
|
72
71
|
return;
|
|
73
72
|
}
|
|
74
|
-
historyList.map(function(item) {
|
|
75
|
-
var newItem = extend({}, item);
|
|
76
|
-
var rawData = item.headers + '\r\n\r\n' + (item.base64 || item.body || '');
|
|
77
|
-
if (!item.dataHash && !item.base64Hash) {
|
|
78
|
-
item[item.base64 ? 'base64Hash' : 'dataHash'] = util.getHexHash(rawData);
|
|
79
|
-
}
|
|
80
|
-
delete newItem.headers;
|
|
81
|
-
delete newItem.body;
|
|
82
|
-
delete newItem.base64;
|
|
83
|
-
return newItem;
|
|
84
|
-
});
|
|
85
73
|
};
|
|
86
74
|
|
|
87
75
|
var descSorter = function(a, b) {
|
|
@@ -124,11 +124,11 @@ module.exports = function (body, callback) {
|
|
|
124
124
|
var zip = new AdmZip();
|
|
125
125
|
sessions.map(function (item, index) {
|
|
126
126
|
item.req.url = item.url;
|
|
127
|
-
var req = util.
|
|
127
|
+
var req = util.getRawReq(item.req);
|
|
128
128
|
var res =
|
|
129
129
|
!item.res || item.res.statusCode == null
|
|
130
130
|
? Buffer.from('')
|
|
131
|
-
: util.
|
|
131
|
+
: util.getRawRes(item.res);
|
|
132
132
|
var name = getName();
|
|
133
133
|
item.index = index;
|
|
134
134
|
zip.addFile('raw/' + name + '_c.txt', req);
|
package/lib/service/service.js
CHANGED
|
@@ -96,12 +96,13 @@ function getFilename(filename, time, count) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function saveSessions(data, cb) {
|
|
99
|
-
var
|
|
99
|
+
var sessions = data.sessions;
|
|
100
|
+
var count = Array.isArray(sessions) && sessions.length;
|
|
100
101
|
if (!count) {
|
|
101
102
|
return cb();
|
|
102
103
|
}
|
|
103
104
|
limiter.push(function (done) {
|
|
104
|
-
gzip(JSON.stringify(
|
|
105
|
+
gzip(JSON.stringify(sessions), function(err, buf) {
|
|
105
106
|
done();
|
|
106
107
|
if (err) {
|
|
107
108
|
return cb(err);
|
|
@@ -109,7 +110,7 @@ function saveSessions(data, cb) {
|
|
|
109
110
|
var filename = getFilename(data.filename, 0, count);
|
|
110
111
|
common.writeFile(path.join(SAVED_SESSIONS_PATH, filename), buf, function(e) {
|
|
111
112
|
!e && saveData({ type: 'savedData', filename: filename, buffer: buf } );
|
|
112
|
-
cb(e);
|
|
113
|
+
cb(e, filename.substring(filename.indexOf('/') + 1));
|
|
113
114
|
});
|
|
114
115
|
});
|
|
115
116
|
});
|
|
@@ -165,7 +166,7 @@ function getTempFiles(list, cb) {
|
|
|
165
166
|
cb(result);
|
|
166
167
|
}
|
|
167
168
|
};
|
|
168
|
-
list
|
|
169
|
+
list.forEach(function(filename) {
|
|
169
170
|
filename = common.getTempFile(filename);
|
|
170
171
|
if (!filename) {
|
|
171
172
|
return execCb();
|
|
@@ -415,8 +416,8 @@ function sessionsHandler() {
|
|
|
415
416
|
res.json({ec: 0});
|
|
416
417
|
});
|
|
417
418
|
app.post('/cgi-bin/saved/save', jsonParser, function(req, res) {
|
|
418
|
-
saveSessions(req.body, function(err) {
|
|
419
|
-
res.json({ec: err ? 2 : 0, em: err ? err.message || 'Error' : undefined});
|
|
419
|
+
saveSessions(req.body, function(err, filename) {
|
|
420
|
+
res.json({ec: err ? 2 : 0, em: err ? err.message || 'Error' : undefined, filename: filename});
|
|
420
421
|
});
|
|
421
422
|
});
|
|
422
423
|
app.post('/cgi-bin/composer', jsonParser, composer.handleRequest);
|
|
@@ -504,7 +505,7 @@ function sessionsHandler() {
|
|
|
504
505
|
common.sendGzip(req, res, data);
|
|
505
506
|
});
|
|
506
507
|
} catch (e) {
|
|
507
|
-
common.sendRes(
|
|
508
|
+
common.sendRes(res, 500, e.stack);
|
|
508
509
|
}
|
|
509
510
|
}
|
|
510
511
|
);
|
package/lib/service/util.js
CHANGED
|
@@ -77,7 +77,7 @@ function getBodyBuffer(data) {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function
|
|
80
|
+
function getRawReq(req) {
|
|
81
81
|
removeEncodingFields(req.headers);
|
|
82
82
|
var headers = getHeadersRaw(req.headers, req.rawHeaderNames);
|
|
83
83
|
var url = String(req.url || '').replace(/^ws/, 'http');
|
|
@@ -85,9 +85,9 @@ function getReqRaw(req) {
|
|
|
85
85
|
return decodeRaw(headers, req);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
exports.
|
|
88
|
+
exports.getRawReq = getRawReq;
|
|
89
89
|
|
|
90
|
-
function
|
|
90
|
+
function getRawRes(res) {
|
|
91
91
|
removeEncodingFields(res.headers);
|
|
92
92
|
var headers = getHeadersRaw(res.headers, res.rawHeaderNames);
|
|
93
93
|
var statusCode = res.statusCode === 'aborted' ? 502 : res.statusCode;
|
|
@@ -98,7 +98,7 @@ function getResRaw(res) {
|
|
|
98
98
|
return decodeRaw(headers, res);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
exports.
|
|
101
|
+
exports.getRawRes = getRawRes;
|
|
102
102
|
|
|
103
103
|
var BODY_SEP = Buffer.from('\r\n\r\n');
|
|
104
104
|
|
|
@@ -425,23 +425,13 @@ function parseFrames(res, content, callback) {
|
|
|
425
425
|
exports.parseFrames = parseFrames;
|
|
426
426
|
|
|
427
427
|
var MAX_SESSIONS_FILES = 2000;
|
|
428
|
-
var SAVED_SESSIONS_FILE_RE = /_([1-9]\d*)_(\d+)$/;
|
|
429
428
|
var DIR_RE = /^\d{6}$/;
|
|
430
429
|
|
|
431
|
-
exports.SAVED_SESSIONS_FILE_RE = SAVED_SESSIONS_FILE_RE;
|
|
432
|
-
|
|
433
430
|
function getFileList(files) {
|
|
434
431
|
var result = [];
|
|
435
432
|
files.forEach(function(file, i) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
var time = RegExp.$2;
|
|
439
|
-
result.push({
|
|
440
|
-
filename: file.slice(0, - time.length - count.length - 2),
|
|
441
|
-
count: +count,
|
|
442
|
-
time: +time
|
|
443
|
-
});
|
|
444
|
-
}
|
|
433
|
+
file = common.getSavedFileItem(file);
|
|
434
|
+
file && result.push(file);
|
|
445
435
|
});
|
|
446
436
|
return result;
|
|
447
437
|
}
|
package/lib/socket-mgr.js
CHANGED
|
@@ -584,7 +584,7 @@ function handleWsReceive(ctx, resTrans, receiveStatus, handleTransform, frameCtx
|
|
|
584
584
|
|
|
585
585
|
function getContext(req, res, hasEvent, sendStatus, receiveStatus, noDecompress) {
|
|
586
586
|
var reqId = req.reqId;
|
|
587
|
-
var ctx =
|
|
587
|
+
var ctx = conns[reqId] = {
|
|
588
588
|
customParser: req.customParser,
|
|
589
589
|
req: req,
|
|
590
590
|
res: res,
|
|
@@ -601,7 +601,7 @@ function getContext(req, res, hasEvent, sendStatus, receiveStatus, noDecompress)
|
|
|
601
601
|
setReceiveStatus: function (status) {
|
|
602
602
|
setConnStatus(ctx, status, receiveStatus);
|
|
603
603
|
}
|
|
604
|
-
}
|
|
604
|
+
};
|
|
605
605
|
initStatus(ctx, req.enable);
|
|
606
606
|
return ctx;
|
|
607
607
|
}
|
|
@@ -718,9 +718,21 @@ exports.handleUpgrade = function (req, res) {
|
|
|
718
718
|
hasEvent && proxy.emit('wsRequest', url);
|
|
719
719
|
cb(null, chunk);
|
|
720
720
|
};
|
|
721
|
-
|
|
721
|
+
var ctx = false;
|
|
722
|
+
if (!hide || frameCtx) {
|
|
723
|
+
ctx = getContext(
|
|
724
|
+
req,
|
|
725
|
+
res,
|
|
726
|
+
hasEvent,
|
|
727
|
+
sendStatus,
|
|
728
|
+
receiveStatus,
|
|
729
|
+
noDecompress
|
|
730
|
+
);
|
|
731
|
+
ctx.hideFrame = req.hideFrame = hideFrame;
|
|
732
|
+
}
|
|
733
|
+
options.ctx = ctx;
|
|
734
|
+
if (!ctx || customParser) {
|
|
722
735
|
reqTrans._transform = resTrans._transform = handleTransform;
|
|
723
|
-
options.ctx = false;
|
|
724
736
|
} else {
|
|
725
737
|
reqTrans.headers = resTrans.headers = res.headers;
|
|
726
738
|
if (reqWrite) {
|
|
@@ -731,15 +743,6 @@ exports.handleUpgrade = function (req, res) {
|
|
|
731
743
|
resWrite.headers = res.headers;
|
|
732
744
|
req.pipeWriter = resWrite;
|
|
733
745
|
}
|
|
734
|
-
var ctx = options.ctx = (conns[reqId] = getContext(
|
|
735
|
-
req,
|
|
736
|
-
res,
|
|
737
|
-
hasEvent,
|
|
738
|
-
sendStatus,
|
|
739
|
-
receiveStatus,
|
|
740
|
-
noDecompress
|
|
741
|
-
));
|
|
742
|
-
ctx.hideFrame = req.hideFrame = hideFrame;
|
|
743
746
|
handleWsSend(ctx, reqTrans, sendStatus, handleTransform, frameCtx);
|
|
744
747
|
handleWsReceive(ctx, resTrans, receiveStatus, handleTransform, frameCtx);
|
|
745
748
|
cleanCacheFrames(ctx, options);
|
|
@@ -798,9 +801,14 @@ exports.handleConnect = function (req, res, isUpgrade) {
|
|
|
798
801
|
if (req._hasClosed) {
|
|
799
802
|
return;
|
|
800
803
|
}
|
|
801
|
-
|
|
804
|
+
var ctx = false;
|
|
805
|
+
if (!hide || frameCtx) {
|
|
806
|
+
ctx = getContext(req, res, hasEvent, sendStatus, receiveStatus);
|
|
807
|
+
ctx.hideFrame = req.hideFrame = hideFrame;
|
|
808
|
+
}
|
|
809
|
+
options.ctx = ctx;
|
|
810
|
+
if (!ctx || customParser) {
|
|
802
811
|
reqTrans._transform = resTrans._transform = handleTransform;
|
|
803
|
-
options.ctx = false;
|
|
804
812
|
} else {
|
|
805
813
|
req.wsExts = res.wsExts = reqTrans.wsExts = resTrans.wsExts = '';
|
|
806
814
|
if (reqWrite) {
|
|
@@ -811,8 +819,6 @@ exports.handleConnect = function (req, res, isUpgrade) {
|
|
|
811
819
|
resWrite.wsExts = '';
|
|
812
820
|
req.pipeWriter = resWrite;
|
|
813
821
|
}
|
|
814
|
-
var ctx = options.ctx = getContext(req, res, hasEvent, sendStatus, receiveStatus);
|
|
815
|
-
ctx.hideFrame = req.hideFrame = hideFrame;
|
|
816
822
|
if (reqRead && reqWrite) {
|
|
817
823
|
handleWsSend(ctx, reqTrans, sendStatus, handleTransform, frameCtx, eventName);
|
|
818
824
|
} else {
|
package/lib/tunnel.js
CHANGED
|
@@ -23,7 +23,6 @@ var X_RE = /^x/;
|
|
|
23
23
|
var STATUS_CODES = require('http').STATUS_CODES || {};
|
|
24
24
|
var getRawHeaderNames = hparser.getRawHeaderNames;
|
|
25
25
|
var formatHeaders = hparser.formatHeaders;
|
|
26
|
-
var getRawHeaders = hparser.getRawHeaders;
|
|
27
26
|
var CRONET_RE = /\bCronet\b/;
|
|
28
27
|
var SYS_HOST_RE = /^(?:[^/:]+\.)?(?:apple|cdn-apple|icloud|office|office365|mzstatic|apple-cloudkit|microsoft|parallels)\.(?:com|cn|com\.cn)$/;
|
|
29
28
|
var TUNNEL_RE = /^tunnel:\/\//;
|
|
@@ -104,6 +103,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
104
103
|
testId: req._testId,
|
|
105
104
|
startTime: now,
|
|
106
105
|
dnsTime: now,
|
|
106
|
+
servername: reqSocket.useSNI === hostname ? undefined : reqSocket.useSNI,
|
|
107
107
|
captureError: true,
|
|
108
108
|
rules: req.rules,
|
|
109
109
|
req: {
|
|
@@ -382,7 +382,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
382
382
|
var reqDelay = util.getMatcherValue(_rules.reqDelay);
|
|
383
383
|
data.requestTime = data.dnsTime = Date.now();
|
|
384
384
|
if (reqDelay > 0) {
|
|
385
|
-
setTimeout(handleConnect, reqDelay);
|
|
385
|
+
util.setDelayTimer(reqSocket, setTimeout(handleConnect, reqDelay));
|
|
386
386
|
} else {
|
|
387
387
|
handleConnect();
|
|
388
388
|
}
|
|
@@ -404,8 +404,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
404
404
|
var proxyUrl;
|
|
405
405
|
if (tunnelPort) {
|
|
406
406
|
proxyUrl = 'proxy://127.0.0.1:' + tunnelPort;
|
|
407
|
-
reqSocket.customParser = req.customParser =
|
|
408
|
-
util.getParserStatus(req);
|
|
407
|
+
reqSocket.customParser = req.customParser = util.getParserStatus(req);
|
|
409
408
|
pluginMgr.addSessionInfo(req, _rules);
|
|
410
409
|
headers[config.PLUGIN_HOOK_NAME_HEADER] =
|
|
411
410
|
config.PLUGIN_HOOKS.TUNNEL;
|
|
@@ -553,7 +552,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
553
552
|
}
|
|
554
553
|
};
|
|
555
554
|
if (reqDelay > 0) {
|
|
556
|
-
setTimeout(connectProxy, reqDelay);
|
|
555
|
+
util.setDelayTimer(reqSocket, setTimeout(connectProxy, reqDelay));
|
|
557
556
|
} else {
|
|
558
557
|
connectProxy();
|
|
559
558
|
}
|
|
@@ -687,7 +686,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
687
686
|
};
|
|
688
687
|
var resDelay = util.getMatcherValue(_rules.resDelay);
|
|
689
688
|
if (resDelay > 0) {
|
|
690
|
-
setTimeout(handleEstablished, resDelay);
|
|
689
|
+
util.setDelayTimer(reqSocket, setTimeout(handleEstablished, resDelay));
|
|
691
690
|
} else {
|
|
692
691
|
handleEstablished();
|
|
693
692
|
}
|
|
@@ -770,23 +769,14 @@ function tunnelProxy(server, proxy, type) {
|
|
|
770
769
|
util.deleteResHeaders(req, resHeaders);
|
|
771
770
|
code = util.getMatcherValue(reqRules.replaceStatus) || code;
|
|
772
771
|
var isSuccess = code == 200;
|
|
773
|
-
var message =
|
|
774
|
-
isSuccess
|
|
775
|
-
? 'Connection Established'
|
|
776
|
-
: STATUS_CODES[code] || 'unknown';
|
|
777
|
-
var statusLine = ['HTTP/1.1', code, message].join(' ');
|
|
772
|
+
var message = isSuccess ? 'Connection Established' : STATUS_CODES[code] || 'unknown';
|
|
778
773
|
var curHeaders = resHeaders;
|
|
779
|
-
var rawData = statusLine;
|
|
780
774
|
if (req.fromComposer) {
|
|
781
775
|
curHeaders = extend({}, resHeaders);
|
|
782
776
|
curHeaders['x-whistle-req-id'] = req.reqId;
|
|
783
777
|
util.setFramesMode(curHeaders, isSuccess && inspect);
|
|
784
778
|
}
|
|
785
|
-
|
|
786
|
-
if (curHeaders) {
|
|
787
|
-
rawData += '\r\n' + curHeaders;
|
|
788
|
-
}
|
|
789
|
-
rawData += '\r\n\r\n';
|
|
779
|
+
var rawData = common.getHttpMeta('HTTP/1.1', code, message, curHeaders, rawHeaderNames);
|
|
790
780
|
try {
|
|
791
781
|
if (code != 200) {
|
|
792
782
|
reqSocket.end(rawData, cb);
|
package/lib/upgrade.js
CHANGED
|
@@ -6,9 +6,7 @@ var util = require('./util');
|
|
|
6
6
|
var config = require('./config');
|
|
7
7
|
var common = require('./util/common');
|
|
8
8
|
|
|
9
|
-
var formatHeaders = hparser.formatHeaders;
|
|
10
9
|
var getRawHeaderNames = hparser.getRawHeaderNames;
|
|
11
|
-
var getRawHeaders = hparser.getRawHeaders;
|
|
12
10
|
var PLUGIN_PATH_RE =
|
|
13
11
|
/^\/(\.\.\.whistle-path\.5b6af7b9884e1165\.\.\.\/\/\/)?(whistle|plugin)\.([^/?#]+)\/?/;
|
|
14
12
|
|
|
@@ -105,12 +103,10 @@ function upgradeHandler(req, socket) {
|
|
|
105
103
|
util.addTunnelData(socket, headers);
|
|
106
104
|
socket._clientId = util.getComposerClientId(headers);
|
|
107
105
|
var getBuffer = function (method, newHeaders, path) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
return Buffer.from(rawData + '\r\n\r\n');
|
|
106
|
+
method = method || 'GET';
|
|
107
|
+
path = path || socket.url || req.url;
|
|
108
|
+
newHeaders = newHeaders || headers;
|
|
109
|
+
return Buffer.from(common.getHttpMeta(method, path, 'HTTP/1.1', newHeaders, req.rawHeaders));
|
|
114
110
|
};
|
|
115
111
|
var sniPlugin = headers[util.SNI_PLUGIN_HEADER];
|
|
116
112
|
if (sniPlugin) {
|
package/lib/util/common.js
CHANGED
|
@@ -12,6 +12,7 @@ var json5 = require('json5');
|
|
|
12
12
|
var extend = require('extend');
|
|
13
13
|
var tls = require('tls');
|
|
14
14
|
var https = require('https');
|
|
15
|
+
var hparser = require('hparser');
|
|
15
16
|
var zlibx = require('./zlib');
|
|
16
17
|
var pkgConf = require('../../package.json');
|
|
17
18
|
var isUtf8 = require('./is-utf8');
|
|
@@ -72,10 +73,22 @@ var TOKEN = '\r\u0000\n\u0003\r';
|
|
|
72
73
|
var PROP_SEP_RE = /(\\*)([|&]|\\[stnrfv])/g;
|
|
73
74
|
var TEMP_FILE_RE = /^(?:\/?temp\/)?([\da-f]{64})(?:\.[\w.-]+)?$/;
|
|
74
75
|
var TEMP_FILES_PATH = path.join(getWhistlePath(), 'temp_files');
|
|
76
|
+
var SAVED_SESSIONS_FILE_RE = /_([1-9]\d*)_(\d+)$/;
|
|
77
|
+
|
|
78
|
+
exports.getSavedFileItem = function(filename) {
|
|
79
|
+
var result = SAVED_SESSIONS_FILE_RE.exec(filename);
|
|
80
|
+
return result && {
|
|
81
|
+
count: +result[1],
|
|
82
|
+
time: +result[2],
|
|
83
|
+
filename: filename.slice(0, - result[1].length - result[2].length - 2)
|
|
84
|
+
};
|
|
85
|
+
};
|
|
75
86
|
|
|
76
87
|
|
|
77
88
|
exports.WHISTLE_UID_HEADER = '_x-whistle-uid_';
|
|
78
89
|
|
|
90
|
+
exports.isUtf8 = isUtf8;
|
|
91
|
+
|
|
79
92
|
exports.getTempFile = function(str) {
|
|
80
93
|
var match = TEMP_FILE_RE.exec(str);
|
|
81
94
|
return match && match[1];
|
|
@@ -670,18 +683,29 @@ exports.isGroup = function(name) {
|
|
|
670
683
|
};
|
|
671
684
|
|
|
672
685
|
var UTF8_RE = /^utf-?8$/i;
|
|
686
|
+
|
|
687
|
+
function getUtf8Buf(buffer, charset) {
|
|
688
|
+
charset = isString(charset) ? charset.trim() : '';
|
|
689
|
+
if (UTF8_RE.test(charset) || isUtf8(buffer)) {
|
|
690
|
+
return buffer;
|
|
691
|
+
}
|
|
692
|
+
try {
|
|
693
|
+
buffer = iconv.encode(buffer, charset || 'GB18030');
|
|
694
|
+
} catch (e) {}
|
|
695
|
+
return buffer;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
exports.getUtf8Buf = getUtf8Buf;
|
|
699
|
+
|
|
700
|
+
|
|
673
701
|
function bufferToString(buffer, encoding) {
|
|
674
|
-
if (
|
|
675
|
-
|
|
676
|
-
} else {
|
|
677
|
-
encoding = null;
|
|
702
|
+
if (!buffer) {
|
|
703
|
+
return '';
|
|
678
704
|
}
|
|
679
|
-
if (Buffer.isBuffer(buffer)
|
|
680
|
-
|
|
681
|
-
buffer = iconv.encode(buffer, encoding || 'GB18030');
|
|
682
|
-
} catch (e) {}
|
|
705
|
+
if (Buffer.isBuffer(buffer)) {
|
|
706
|
+
buffer = getUtf8Buf(buffer, encoding);
|
|
683
707
|
}
|
|
684
|
-
return String(buffer
|
|
708
|
+
return String(buffer);
|
|
685
709
|
}
|
|
686
710
|
|
|
687
711
|
exports.bufferToString = bufferToString;
|
|
@@ -697,9 +721,9 @@ function isUrlEncoded(req) {
|
|
|
697
721
|
exports.isUrlEncoded = isUrlEncoded;
|
|
698
722
|
|
|
699
723
|
function readStream(stream, callback) {
|
|
700
|
-
var buffer =
|
|
724
|
+
var buffer = [];
|
|
701
725
|
stream.on('data', function(chunk) {
|
|
702
|
-
buffer
|
|
726
|
+
buffer.push(chunk);
|
|
703
727
|
});
|
|
704
728
|
stream.once('end', function() {
|
|
705
729
|
var buf;
|
|
@@ -708,6 +732,7 @@ function readStream(stream, callback) {
|
|
|
708
732
|
var err;
|
|
709
733
|
var jsonErr;
|
|
710
734
|
stream.zlib = zlibx;
|
|
735
|
+
buffer = buffer.length > 1 ? Buffer.concat(buffer) : (buffer[0] || null);
|
|
711
736
|
var encoding = stream.headers && stream.headers['content-encoding'];
|
|
712
737
|
var getBuffer = function(cb) {
|
|
713
738
|
if (err || buf !== undefined) {
|
|
@@ -851,9 +876,24 @@ exports.getHostPort = function(str) {
|
|
|
851
876
|
}
|
|
852
877
|
};
|
|
853
878
|
|
|
879
|
+
function clearDelayTimer(socket) {
|
|
880
|
+
var timer = socket._w2Timer_;
|
|
881
|
+
if (timer) {
|
|
882
|
+
clearTimeout(timer);
|
|
883
|
+
socket._w2Timer_ = null;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
exports.clearDelayTimer = clearDelayTimer;
|
|
888
|
+
exports.setDelayTimer = function (socket, id) {
|
|
889
|
+
socket._w2Timer_ = id;
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
|
|
854
893
|
exports.onSocketEnd = function(socket, callback) {
|
|
855
894
|
var execCallback = function (err) {
|
|
856
895
|
socket._hasError = true;
|
|
896
|
+
clearDelayTimer(socket);
|
|
857
897
|
if (callback) {
|
|
858
898
|
callback(err);
|
|
859
899
|
callback = null;
|
|
@@ -969,6 +1009,10 @@ function isString(str) {
|
|
|
969
1009
|
|
|
970
1010
|
exports.isString = isString;
|
|
971
1011
|
|
|
1012
|
+
exports.isStr = function(str) {
|
|
1013
|
+
return typeof str === 'string';
|
|
1014
|
+
};
|
|
1015
|
+
|
|
972
1016
|
function isSafeNumStr(str) {
|
|
973
1017
|
if (str == '0') {
|
|
974
1018
|
return true;
|
|
@@ -1428,6 +1472,18 @@ exports.sendGzip = function (req, res, data) {
|
|
|
1428
1472
|
});
|
|
1429
1473
|
};
|
|
1430
1474
|
|
|
1475
|
+
exports.toString = function (str) {
|
|
1476
|
+
if (str != null) {
|
|
1477
|
+
if (typeof str === 'string') {
|
|
1478
|
+
return str;
|
|
1479
|
+
}
|
|
1480
|
+
try {
|
|
1481
|
+
return JSON.stringify(str) || '';
|
|
1482
|
+
} catch (e) {}
|
|
1483
|
+
}
|
|
1484
|
+
return '';
|
|
1485
|
+
};
|
|
1486
|
+
|
|
1431
1487
|
exports.sendGzipText = function(req, res, headers, text, gzipText) {
|
|
1432
1488
|
if (!text || !canGzip(req) || (!gzipText && text.length < GZIP_THRESHOLD)) {
|
|
1433
1489
|
headers && res.writeHead(200, headers);
|
|
@@ -2045,3 +2101,14 @@ var COMMENT_RE = /#[^\r\n]*/g;
|
|
|
2045
2101
|
exports.removeComment = function(text) {
|
|
2046
2102
|
return text.replace(COMMENT_RE, '').trim();
|
|
2047
2103
|
};
|
|
2104
|
+
|
|
2105
|
+
function getHttpMeta(f1, f2, f3, headers, rawHeaders) {
|
|
2106
|
+
var statusLine = [f1, f2, f3].join(' ');
|
|
2107
|
+
if (headers) {
|
|
2108
|
+
headers = hparser.formatHeaders(headers, rawHeaders);
|
|
2109
|
+
headers = hparser.getRawHeaders(headers);
|
|
2110
|
+
}
|
|
2111
|
+
return (headers ? statusLine + '\r\n' + headers : statusLine) + '\r\n\r\n';
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
exports.getHttpMeta = getHttpMeta;
|