whistle 2.9.35 → 2.9.36-beta
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/worker.js +84 -0
- package/biz/index.js +1 -0
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +46 -46
- package/biz/webui/lib/index.js +12 -0
- package/lib/https/index.js +4 -6
- package/lib/inspectors/res.js +2 -2
- package/lib/plugins/get-plugins-sync.js +2 -0
- package/lib/plugins/index.js +6 -1
- package/lib/plugins/load-plugin.js +74 -6
- package/lib/plugins/util.js +45 -0
- package/lib/util/common.js +10 -0
- package/lib/util/index.js +126 -54
- package/package.json +2 -2
package/biz/webui/lib/index.js
CHANGED
|
@@ -18,6 +18,7 @@ var setProxy = require('./proxy');
|
|
|
18
18
|
var rulesUtil = require('../../../lib/rules/util');
|
|
19
19
|
var getRootCAFile = require('../../../lib/https/ca').getRootCAFile;
|
|
20
20
|
var config = require('../../../lib/config');
|
|
21
|
+
var getWorker = require('../../../lib/plugins/util').getWorker;
|
|
21
22
|
var loadAuthPlugins = require('../../../lib/plugins').loadAuthPlugins;
|
|
22
23
|
|
|
23
24
|
var PARSE_CONF = { extended: true, limit: '3mb'};
|
|
@@ -422,6 +423,17 @@ app.get('/values', function(req, res) {
|
|
|
422
423
|
sendText(res, rulesUtil.values.get(name));
|
|
423
424
|
});
|
|
424
425
|
|
|
426
|
+
app.get('/web-worker.js', urlencodedParser, function(req, res) {
|
|
427
|
+
var body = getWorker(req.query.id);
|
|
428
|
+
if (!body) {
|
|
429
|
+
return res.status(404).end('Not Found');
|
|
430
|
+
}
|
|
431
|
+
res.writeHead(200, {
|
|
432
|
+
'Content-Type': 'application/javascript; charset=utf-8'
|
|
433
|
+
});
|
|
434
|
+
res.end(body);
|
|
435
|
+
});
|
|
436
|
+
|
|
425
437
|
app.all('/cgi-bin/*', function(req, res, next) {
|
|
426
438
|
req.isUploadReq = UPLOAD_URLS.indexOf(req.path) !== -1;
|
|
427
439
|
return req.isUploadReq ? uploadUrlencodedParser(req, res, next) : urlencodedParser(req, res, next);
|
package/lib/https/index.js
CHANGED
|
@@ -676,11 +676,10 @@ function resolveWebsocket(socket, wss) {
|
|
|
676
676
|
newUrl = util.parsePathReplace(newUrl, urlReplace) || newUrl;
|
|
677
677
|
if (newUrl !== fullUrl) {
|
|
678
678
|
fullUrl = newUrl;
|
|
679
|
-
options = util.parseUrl(fullUrl);
|
|
680
679
|
socket._realUrl = newUrl;
|
|
681
|
-
} else {
|
|
682
|
-
options = util.parseUrl(fullUrl);
|
|
683
680
|
}
|
|
681
|
+
options = util.parseUrl(fullUrl);
|
|
682
|
+
socket._w2hostname = options.hostname;
|
|
684
683
|
data.realUrl = fullUrl;
|
|
685
684
|
var host = (headers.host = options.host);
|
|
686
685
|
socket._origin = headers.origin;
|
|
@@ -726,9 +725,8 @@ function resolveWebsocket(socket, wss) {
|
|
|
726
725
|
if (socket._origin && origin && origin !== '*') {
|
|
727
726
|
curResHeaders['access-control-allow-origin'] = socket._origin;
|
|
728
727
|
}
|
|
729
|
-
|
|
730
|
-
util.
|
|
731
|
-
util.setResCookies(resRuleData, cookies, socket);
|
|
728
|
+
util.setResCors(res, cors, socket);
|
|
729
|
+
util.setResCookies(res, cookies, socket);
|
|
732
730
|
util.setResponseFor(_rules, curResHeaders, socket, socket.hostIp);
|
|
733
731
|
var delResHeaders = util.parseDelProps(socket).resHeaders;
|
|
734
732
|
Object.keys(delResHeaders).forEach(function (name) {
|
package/lib/inspectors/res.js
CHANGED
|
@@ -860,8 +860,8 @@ module.exports = function (req, res, next) {
|
|
|
860
860
|
);
|
|
861
861
|
}
|
|
862
862
|
|
|
863
|
-
util.setResCookies(
|
|
864
|
-
util.setResCors(
|
|
863
|
+
util.setResCookies(_res, cookies, req);
|
|
864
|
+
util.setResCors(_res, cors, req);
|
|
865
865
|
|
|
866
866
|
var cache = util.getMatcherValue(resRules.cache);
|
|
867
867
|
var enable = req.enable;
|
|
@@ -113,6 +113,8 @@ module.exports = function () {
|
|
|
113
113
|
tunnelKey: util.getTunnelKey(conf),
|
|
114
114
|
staticDir: util.getStaticDir(conf),
|
|
115
115
|
pluginVars: util.getPluginVarsConf(conf),
|
|
116
|
+
networkColumn: util.getNetworkColumn(conf),
|
|
117
|
+
webWorker: pluginUtil.readWorkerSync(dir, conf),
|
|
116
118
|
networkMenus: util.getPluginMenu(
|
|
117
119
|
conf.networkMenus || conf.networkMenu,
|
|
118
120
|
simpleName
|
package/lib/plugins/index.js
CHANGED
|
@@ -375,6 +375,7 @@ function readPackages(obj, callback) {
|
|
|
375
375
|
0;
|
|
376
376
|
newPkg.rulesUrl = util.getCgiUrl(conf.rulesUrl);
|
|
377
377
|
newPkg.valuesUrl = util.getCgiUrl(conf.valuesUrl);
|
|
378
|
+
newPkg.networkColumn = util.getNetworkColumn(conf);
|
|
378
379
|
newPkg.networkMenus = util.getPluginMenu(
|
|
379
380
|
conf.networkMenus || conf.networkMenu,
|
|
380
381
|
simpleName
|
|
@@ -436,7 +437,10 @@ function readPackages(obj, callback) {
|
|
|
436
437
|
result,
|
|
437
438
|
simpleName
|
|
438
439
|
);
|
|
439
|
-
|
|
440
|
+
pluginUtil.readWorker(newPkg.path, conf, function(hash) {
|
|
441
|
+
newPkg.webWorker = hash;
|
|
442
|
+
callbackHandler();
|
|
443
|
+
});
|
|
440
444
|
}
|
|
441
445
|
);
|
|
442
446
|
}
|
|
@@ -512,6 +516,7 @@ setTimeout(checkUpdate, 5000);
|
|
|
512
516
|
uninstallPlugins && pluginMgr.emit('uninstall', uninstallPlugins);
|
|
513
517
|
updatePlugins && pluginMgr.emit('update', updatePlugins);
|
|
514
518
|
pluginMgr.emit('updateRules');
|
|
519
|
+
pluginUtil.resetWorkers(allPlugins);
|
|
515
520
|
}
|
|
516
521
|
update();
|
|
517
522
|
});
|
|
@@ -899,6 +899,19 @@ function toBinary(data) {
|
|
|
899
899
|
return Buffer.from(data);
|
|
900
900
|
}
|
|
901
901
|
|
|
902
|
+
function getCustomBody(body, headers) {
|
|
903
|
+
if (body && typeof body.pipe === 'function') {
|
|
904
|
+
delete headers['content-length'];
|
|
905
|
+
return body;
|
|
906
|
+
}
|
|
907
|
+
body = toBinary(body) || '';
|
|
908
|
+
if (headers['content-length'] != null) {
|
|
909
|
+
headers['content-length'] = body ? body.length : 0;
|
|
910
|
+
delete headers['transfer-encoding'];
|
|
911
|
+
}
|
|
912
|
+
return body;
|
|
913
|
+
}
|
|
914
|
+
|
|
902
915
|
function wrapTunnelWriter(socket, toServer) {
|
|
903
916
|
var write = socket.write;
|
|
904
917
|
var end = socket.end;
|
|
@@ -1569,6 +1582,7 @@ module.exports = async function (options, callback) {
|
|
|
1569
1582
|
wrapWsWriter: wrapWsWriter
|
|
1570
1583
|
}, cb);
|
|
1571
1584
|
};
|
|
1585
|
+
|
|
1572
1586
|
var initServers = function (_ctx) {
|
|
1573
1587
|
ctx = _ctx || ctx;
|
|
1574
1588
|
var execPlugin = require(options.value) || '';
|
|
@@ -2066,16 +2080,70 @@ module.exports = async function (options, callback) {
|
|
|
2066
2080
|
return client;
|
|
2067
2081
|
};
|
|
2068
2082
|
req.passThrough = function (uri, newTrailers) {
|
|
2069
|
-
var
|
|
2070
|
-
|
|
2083
|
+
var handleReq;
|
|
2084
|
+
var handleRes;
|
|
2085
|
+
if (typeof uri === 'function') {
|
|
2086
|
+
handleReq = uri;
|
|
2087
|
+
uri = null;
|
|
2088
|
+
}
|
|
2089
|
+
if (typeof newTrailers === 'function') {
|
|
2090
|
+
handleRes = newTrailers;
|
|
2091
|
+
newTrailers = null;
|
|
2092
|
+
}
|
|
2093
|
+
var _request = function(reqBody, _uri) {
|
|
2094
|
+
var client = req.request(_uri || uri, function (_res) {
|
|
2095
|
+
var _response = function(resBody, trailers) {
|
|
2096
|
+
res.writeHead(
|
|
2071
2097
|
_res.statusCode,
|
|
2072
2098
|
_res.statusMessage,
|
|
2073
2099
|
_res.headers
|
|
2074
2100
|
);
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2101
|
+
appendTrailers(_res, res, trailers || newTrailers, req);
|
|
2102
|
+
if (resBody === undefined) {
|
|
2103
|
+
_res.pipe(res);
|
|
2104
|
+
} else if (resBody.pipe) {
|
|
2105
|
+
resBody.pipe(res);
|
|
2106
|
+
} else {
|
|
2107
|
+
res.end(resBody);
|
|
2108
|
+
}
|
|
2109
|
+
};
|
|
2110
|
+
if (handleRes) {
|
|
2111
|
+
common.readStream(_res, function(buffer) {
|
|
2112
|
+
handleRes(buffer, function(result) {
|
|
2113
|
+
if (result) {
|
|
2114
|
+
req.setResRules(result.rules);
|
|
2115
|
+
_response(getCustomBody(result.body, _res.headers), result.trailers);
|
|
2116
|
+
} else {
|
|
2117
|
+
_response('');
|
|
2118
|
+
}
|
|
2119
|
+
});
|
|
2120
|
+
});
|
|
2121
|
+
} else {
|
|
2122
|
+
_response();
|
|
2123
|
+
}
|
|
2124
|
+
});
|
|
2125
|
+
if (reqBody === undefined) {
|
|
2126
|
+
req.pipe(client);
|
|
2127
|
+
} else if (reqBody.pipe) {
|
|
2128
|
+
reqBody.pipe(client);
|
|
2129
|
+
} else {
|
|
2130
|
+
client.end(reqBody);
|
|
2131
|
+
}
|
|
2132
|
+
};
|
|
2133
|
+
if (handleReq) {
|
|
2134
|
+
common.readStream(req, function(buffer) {
|
|
2135
|
+
handleReq(buffer, function(result) {
|
|
2136
|
+
if (result) {
|
|
2137
|
+
req.setReqRules(result.rules);
|
|
2138
|
+
_request(getCustomBody(result.body, req.headers) || '', result.uri || result.url);
|
|
2139
|
+
} else {
|
|
2140
|
+
_request('');
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
});
|
|
2144
|
+
} else {
|
|
2145
|
+
_request();
|
|
2146
|
+
}
|
|
2079
2147
|
};
|
|
2080
2148
|
httpServer.emit('request', req, res);
|
|
2081
2149
|
}
|
package/lib/plugins/util.js
CHANGED
|
@@ -12,6 +12,51 @@ var PLUGIN_NAME_RE = /^(?:@[\w-]+\/)?(whistle\.[a-z\d_\-]+)$/;
|
|
|
12
12
|
var DEV_PLUGINS_PATH = config.DEV_PLUGINS_PATH;
|
|
13
13
|
var MAX_EXPIRE = 36000;
|
|
14
14
|
var UTF8_OPTIONS = { encoding: 'utf8' };
|
|
15
|
+
var workerScript = util.readFileSync(path.join(__dirname, '../../assets/js/worker.js'));
|
|
16
|
+
var workers = {};
|
|
17
|
+
|
|
18
|
+
function replaceScript(ctn) {
|
|
19
|
+
return workerScript.replace('/*sourcecode*/', ctn);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
exports.readWorkerSync = function(root, conf) {
|
|
23
|
+
var file = util.getWebWorker(conf);
|
|
24
|
+
file = file && util.readFileSync(path.join(root, file));
|
|
25
|
+
if (!file) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
var id = util.createHash(file);
|
|
29
|
+
workers[id] = replaceScript(file);
|
|
30
|
+
return id;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
exports.readWorker = function(root, conf, callback) {
|
|
34
|
+
var file = util.getWebWorker(conf);
|
|
35
|
+
if (!file) {
|
|
36
|
+
return callback();
|
|
37
|
+
}
|
|
38
|
+
readFile(path.join(root, file), function(err, ctn) {
|
|
39
|
+
if (err || !ctn) {
|
|
40
|
+
return callback();
|
|
41
|
+
}
|
|
42
|
+
var id = util.createHash(ctn);
|
|
43
|
+
workers[id] = replaceScript(ctn);
|
|
44
|
+
callback(id);
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
exports.getWorker = function(id) {
|
|
49
|
+
return workers[id];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
exports.resetWorkers = function(plugins) {
|
|
53
|
+
var _workers = {};
|
|
54
|
+
Object.keys(plugins).forEach(function(key) {
|
|
55
|
+
var plugin = plugins[key];
|
|
56
|
+
_workers[plugin.webWorker] = workers[plugin.webWorker];
|
|
57
|
+
});
|
|
58
|
+
workers = _workers;
|
|
59
|
+
};
|
|
15
60
|
|
|
16
61
|
function isOrgModule(name) {
|
|
17
62
|
return ORG_RE.test(name);
|
package/lib/util/common.js
CHANGED
|
@@ -324,3 +324,13 @@ exports.wrapRuleValue = function(key, value, size, policy) {
|
|
|
324
324
|
exports.isGroup = function(name) {
|
|
325
325
|
return name && name[0] === '\r';
|
|
326
326
|
};
|
|
327
|
+
|
|
328
|
+
exports.readStream = function(stream, callback) {
|
|
329
|
+
var buffer = null;
|
|
330
|
+
stream.on('data', function(chunk) {
|
|
331
|
+
buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
|
|
332
|
+
});
|
|
333
|
+
stream.once('end', function() {
|
|
334
|
+
callback(buffer);
|
|
335
|
+
});
|
|
336
|
+
};
|
package/lib/util/index.js
CHANGED
|
@@ -61,6 +61,11 @@ var HTTP_RE = /^https?:\/\/[^/?]/;
|
|
|
61
61
|
var SEP_RE = /[|&]/;
|
|
62
62
|
var ctxTimer;
|
|
63
63
|
var END_RE = /[/\\]$/;
|
|
64
|
+
var EXPIRED_SEC = -123456;
|
|
65
|
+
var EXP_COOKIE = { maxAge: EXPIRED_SEC, path: '/' };
|
|
66
|
+
var EXP_SECURE_COOKIE = { maxAge: EXPIRED_SEC, path: '/', secure: true };
|
|
67
|
+
var EXP_COOKIE_D = { maxAge: EXPIRED_SEC, path: '/' };
|
|
68
|
+
var EXP_SECURE_COOKIE_D = { maxAge: EXPIRED_SEC, path: '/', secure: true };
|
|
64
69
|
var resetContext = function () {
|
|
65
70
|
ctxTimer = null;
|
|
66
71
|
CONTEXT = vm.createContext();
|
|
@@ -705,6 +710,12 @@ if (isString(hostname)) {
|
|
|
705
710
|
simpleHostname = simpleHostname ? simpleHostname + '.' : '';
|
|
706
711
|
}
|
|
707
712
|
|
|
713
|
+
function createHash(str) {
|
|
714
|
+
return crypto.createHash('sha256').update(str).digest('hex');
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
exports.createHash = createHash;
|
|
718
|
+
|
|
708
719
|
var clientId = [
|
|
709
720
|
hostname,
|
|
710
721
|
os.platform(),
|
|
@@ -1927,7 +1938,9 @@ exports.replaceUrlQueryString = replaceUrlQueryString;
|
|
|
1927
1938
|
exports.decodeBuffer = fileMgr.decode;
|
|
1928
1939
|
|
|
1929
1940
|
function setHeaders(data, obj) {
|
|
1930
|
-
|
|
1941
|
+
if (!data.headers) {
|
|
1942
|
+
data.headers = {};
|
|
1943
|
+
}
|
|
1931
1944
|
for (var i in obj) {
|
|
1932
1945
|
data.headers[i] = obj[i];
|
|
1933
1946
|
}
|
|
@@ -1937,7 +1950,9 @@ function setHeaders(data, obj) {
|
|
|
1937
1950
|
exports.setHeaders = setHeaders;
|
|
1938
1951
|
|
|
1939
1952
|
function setHeader(data, name, value) {
|
|
1940
|
-
|
|
1953
|
+
if (!data.headers) {
|
|
1954
|
+
data.headers = {};
|
|
1955
|
+
}
|
|
1941
1956
|
data.headers[name] = value;
|
|
1942
1957
|
return data;
|
|
1943
1958
|
}
|
|
@@ -2539,6 +2554,30 @@ exports.getPluginMenu = function (menus, pluginName) {
|
|
|
2539
2554
|
return result;
|
|
2540
2555
|
};
|
|
2541
2556
|
|
|
2557
|
+
exports.getNetworkColumn = function(conf) {
|
|
2558
|
+
var column = conf.networkColumn;
|
|
2559
|
+
var title = column && (column.title || column.name);
|
|
2560
|
+
var key = title && column.key;
|
|
2561
|
+
if (!isString(title) || !isString(key)) {
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2564
|
+
return {
|
|
2565
|
+
title: title.substring(0, 16),
|
|
2566
|
+
key: key.substring(0, 72),
|
|
2567
|
+
showTitle: (column.showTips || column.showTitle) ? 1 : undefined,
|
|
2568
|
+
width: Math.min(360, Math.max(parseInt(column.width) || 120, 70))
|
|
2569
|
+
};
|
|
2570
|
+
};
|
|
2571
|
+
|
|
2572
|
+
exports.getWebWorker = function(conf) {
|
|
2573
|
+
var webWorker = conf.webWorker;
|
|
2574
|
+
if (!isString(webWorker)) {
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
webWorker = toRelPath(webWorker);
|
|
2578
|
+
return webWorker && webWorker.length <= 120 ? webWorker : undefined;
|
|
2579
|
+
};
|
|
2580
|
+
|
|
2542
2581
|
var MAX_HINT_LEN = 512;
|
|
2543
2582
|
var MAX_VAR_LEN = 100;
|
|
2544
2583
|
|
|
@@ -2621,6 +2660,10 @@ exports.getPluginVarsConf = function (conf) {
|
|
|
2621
2660
|
return true;
|
|
2622
2661
|
};
|
|
2623
2662
|
|
|
2663
|
+
function toRelPath(str) {
|
|
2664
|
+
return str.replace(/^\/+/, '');
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2624
2667
|
exports.getStaticDir = function (conf) {
|
|
2625
2668
|
var staticDir = conf.staticDir;
|
|
2626
2669
|
if (
|
|
@@ -2631,7 +2674,7 @@ exports.getStaticDir = function (conf) {
|
|
|
2631
2674
|
) {
|
|
2632
2675
|
return;
|
|
2633
2676
|
}
|
|
2634
|
-
return staticDir.replace(/^\/+/, '');
|
|
2677
|
+
return toRelPath(staticDir.replace(/^\/+/, ''));
|
|
2635
2678
|
};
|
|
2636
2679
|
|
|
2637
2680
|
function toString(str) {
|
|
@@ -2700,7 +2743,7 @@ var RES_HEADER_RE = /^res\.?H(?:eaders?)?\.(.+)$/i;
|
|
|
2700
2743
|
var TRAILER_RE = /trailer\.(.+)$/;
|
|
2701
2744
|
var HEADER_RE = /^headers\.(.+)$/;
|
|
2702
2745
|
var REQ_COOKIE_RE = /^req\.?C(?:ookies?)?\.(.+)$/i;
|
|
2703
|
-
var RES_COOKIE_RE = /^
|
|
2746
|
+
var RES_COOKIE_RE = /^res\.?C(?:ookies?)?\.(.+)$/i;
|
|
2704
2747
|
var COOKIE_RE = /^cookies?\.(.+)$/i;
|
|
2705
2748
|
var QUERY_RE = /^(?:query|urlParams?)\.(.+)$/i;
|
|
2706
2749
|
|
|
@@ -2727,14 +2770,30 @@ function parseDelReqCookies(req) {
|
|
|
2727
2770
|
Object.keys(deleteRule).forEach(function (prop) {
|
|
2728
2771
|
if (REQ_COOKIE_RE.test(prop) || COOKIE_RE.test(prop)) {
|
|
2729
2772
|
reqCookies = reqCookies || {};
|
|
2730
|
-
reqCookies[RegExp.$1
|
|
2773
|
+
reqCookies[RegExp.$1] = 1;
|
|
2731
2774
|
}
|
|
2732
2775
|
});
|
|
2733
2776
|
}
|
|
2734
2777
|
return reqCookies;
|
|
2735
2778
|
}
|
|
2736
2779
|
|
|
2737
|
-
|
|
2780
|
+
function getDomain(req) {
|
|
2781
|
+
var host = req._w2hostname;
|
|
2782
|
+
if (typeof host !== 'string') {
|
|
2783
|
+
return;
|
|
2784
|
+
}
|
|
2785
|
+
host = host.split('.');
|
|
2786
|
+
var len = host.length;
|
|
2787
|
+
if (len < 3) {
|
|
2788
|
+
return;
|
|
2789
|
+
}
|
|
2790
|
+
if (len === 3) {
|
|
2791
|
+
host[0] = '';
|
|
2792
|
+
} else {
|
|
2793
|
+
host.shift();
|
|
2794
|
+
}
|
|
2795
|
+
return host.join('.');
|
|
2796
|
+
}
|
|
2738
2797
|
|
|
2739
2798
|
function parseDelResCookies(req) {
|
|
2740
2799
|
var resCookies;
|
|
@@ -2743,15 +2802,20 @@ function parseDelResCookies(req) {
|
|
|
2743
2802
|
Object.keys(deleteRule).forEach(function (prop) {
|
|
2744
2803
|
if (RES_COOKIE_RE.test(prop) || COOKIE_RE.test(prop)) {
|
|
2745
2804
|
resCookies = resCookies || {};
|
|
2746
|
-
|
|
2805
|
+
var list = [EXP_COOKIE, EXP_SECURE_COOKIE];
|
|
2806
|
+
resCookies[RegExp.$1] = list;
|
|
2807
|
+
var domain = getDomain(req);
|
|
2808
|
+
if (domain) {
|
|
2809
|
+
EXP_COOKIE_D.domain = domain;
|
|
2810
|
+
EXP_SECURE_COOKIE_D.domain = domain;
|
|
2811
|
+
list.push(EXP_COOKIE_D, EXP_SECURE_COOKIE_D);
|
|
2812
|
+
}
|
|
2747
2813
|
}
|
|
2748
2814
|
});
|
|
2749
2815
|
}
|
|
2750
2816
|
return resCookies;
|
|
2751
2817
|
}
|
|
2752
2818
|
|
|
2753
|
-
exports.parseDelResCookies = parseDelResCookies;
|
|
2754
|
-
|
|
2755
2819
|
function parseDelProps(req) {
|
|
2756
2820
|
var deleteRule = req['delete'];
|
|
2757
2821
|
var reqHeaders = {};
|
|
@@ -2994,79 +3058,87 @@ exports.setReqCookies = function (data, cookies, curCookies, req) {
|
|
|
2994
3058
|
cookies = Object.keys(result)
|
|
2995
3059
|
.map(function (name) {
|
|
2996
3060
|
var value = result[name];
|
|
2997
|
-
return name + (value == null ? '' :
|
|
3061
|
+
return name + '=' + (value == null ? '' : value);
|
|
2998
3062
|
})
|
|
2999
3063
|
.join('; ');
|
|
3000
3064
|
setHeader(data, 'cookie', cookies);
|
|
3001
3065
|
};
|
|
3002
3066
|
|
|
3067
|
+
function getCookieItem(name, cookie) {
|
|
3068
|
+
if (!cookie || typeof cookie != 'object') {
|
|
3069
|
+
cookie = cookie ? escapeValue(cookie) : cookie;
|
|
3070
|
+
return name + '=' + (cookie == null ? '' : cookie);
|
|
3071
|
+
}
|
|
3072
|
+
var attrs = [escapeValue(cookie.value)];
|
|
3073
|
+
var maxAge = cookie.maxAge || cookie.maxage ||
|
|
3074
|
+
cookie.MaxAge || cookie['Max-Age'] || cookie['max-age'];
|
|
3075
|
+
maxAge = parseInt(cookie.maxAge, 10);
|
|
3076
|
+
if (!Number.isNaN(maxAge)) {
|
|
3077
|
+
attrs.push('Expires=' + new Date(Date.now() + maxAge * 1000).toGMTString());
|
|
3078
|
+
attrs.push('Max-Age=' + (maxAge === EXPIRED_SEC ? 0 : maxAge));
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
(cookie.secure || cookie.Secure) && attrs.push('Secure');
|
|
3082
|
+
(cookie.httpOnly || cookie.HttpOnly || cookie.httponly) && attrs.push('HttpOnly');
|
|
3083
|
+
var path = cookie.path || cookie.Path;
|
|
3084
|
+
var domain = cookie.domain || cookie.Domain;
|
|
3085
|
+
var sameSite = cookie.sameSite || cookie.samesite || cookie.SameSite;
|
|
3086
|
+
path && attrs.push('Path=' + path);
|
|
3087
|
+
domain && attrs.push('Domain=' + domain);
|
|
3088
|
+
sameSite && attrs.push('SameSite=' + sameSite);
|
|
3089
|
+
return name + attrs.join('; ');
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
function addMapArr(obj, key, value) {
|
|
3093
|
+
var arr = obj[key] || [];
|
|
3094
|
+
arr.push(value);
|
|
3095
|
+
obj[key] = arr;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3003
3098
|
exports.setResCookies = function (data, cookies, req) {
|
|
3099
|
+
var delKeys = parseDelResCookies(req);
|
|
3100
|
+
if (delKeys) {
|
|
3101
|
+
cookies = cookies ? extend(cookies, delKeys) : delKeys;
|
|
3102
|
+
}
|
|
3004
3103
|
var list = cookies && Object.keys(cookies);
|
|
3005
3104
|
var notEmpty = list && list.length;
|
|
3006
|
-
|
|
3007
|
-
var curCookies = data.headers && data.headers['set-cookie'];
|
|
3008
|
-
if (!notEmpty && (!delKeys || !curCookies)) {
|
|
3105
|
+
if (!notEmpty) {
|
|
3009
3106
|
return;
|
|
3010
3107
|
}
|
|
3108
|
+
var curCookies = data.headers && data.headers['set-cookie'];
|
|
3011
3109
|
if (!Array.isArray(curCookies)) {
|
|
3012
3110
|
curCookies = curCookies ? [curCookies + ''] : [];
|
|
3013
3111
|
}
|
|
3014
3112
|
|
|
3015
|
-
var
|
|
3113
|
+
var curData = {};
|
|
3016
3114
|
curCookies.forEach(function (cookie) {
|
|
3017
3115
|
var index = cookie.indexOf('=');
|
|
3018
3116
|
var key = cookie;
|
|
3019
|
-
var value = null;
|
|
3020
3117
|
if (index !== -1) {
|
|
3021
3118
|
key = cookie.substring(0, index);
|
|
3022
|
-
value = cookie.substring(index + 1);
|
|
3023
|
-
}
|
|
3024
|
-
if (!delKeys || !delKeys[key]) {
|
|
3025
|
-
result[key] = value;
|
|
3026
3119
|
}
|
|
3120
|
+
addMapArr(curData, key, cookie);
|
|
3027
3121
|
});
|
|
3028
|
-
|
|
3122
|
+
var result = {};
|
|
3029
3123
|
list.forEach(function (name) {
|
|
3030
3124
|
var cookie = cookies[name];
|
|
3031
|
-
var origName = name;
|
|
3032
3125
|
name = escapeName(name);
|
|
3033
|
-
if (
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
result[name] = cookie ? escapeValue(cookie) : cookie;
|
|
3126
|
+
if (Array.isArray(cookie)) {
|
|
3127
|
+
cookie.forEach(function(value) {
|
|
3128
|
+
addMapArr(result, name, getCookieItem(name, value));
|
|
3129
|
+
});
|
|
3038
3130
|
} else {
|
|
3039
|
-
|
|
3040
|
-
var value = cookie.value;
|
|
3041
|
-
attrs.push(escapeValue(value));
|
|
3042
|
-
var maxAge =
|
|
3043
|
-
cookie.maxAge ||
|
|
3044
|
-
cookie.maxage ||
|
|
3045
|
-
cookie['Max-Age'] ||
|
|
3046
|
-
cookie['max-age'];
|
|
3047
|
-
maxAge = parseInt(cookie.maxAge, 10);
|
|
3048
|
-
if (!Number.isNaN(maxAge)) {
|
|
3049
|
-
attrs.push(
|
|
3050
|
-
'Expires=' + new Date(Date.now() + maxAge * 1000).toGMTString()
|
|
3051
|
-
);
|
|
3052
|
-
attrs.push('Max-Age=' + maxAge);
|
|
3053
|
-
}
|
|
3054
|
-
|
|
3055
|
-
cookie.secure && attrs.push('Secure');
|
|
3056
|
-
cookie.path && attrs.push('Path=' + cookie.path);
|
|
3057
|
-
cookie.domain && attrs.push('Domain=' + cookie.domain);
|
|
3058
|
-
(cookie.httpOnly || cookie.httponly) && attrs.push('HttpOnly');
|
|
3059
|
-
var sameSite = cookie.sameSite || cookie.samesite || cookie.SameSite;
|
|
3060
|
-
sameSite && attrs.push('SameSite=' + sameSite);
|
|
3061
|
-
result[name] = attrs.join('; ');
|
|
3131
|
+
addMapArr(result, name, getCookieItem(name, cookie));
|
|
3062
3132
|
}
|
|
3063
3133
|
});
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3134
|
+
extend(curData, result);
|
|
3135
|
+
result = [];
|
|
3136
|
+
Object.keys(curData).forEach(function (name) {
|
|
3137
|
+
curData[name].forEach(function(value) {
|
|
3138
|
+
result.push(value);
|
|
3139
|
+
});
|
|
3068
3140
|
});
|
|
3069
|
-
setHeader(data, 'set-cookie',
|
|
3141
|
+
setHeader(data, 'set-cookie', result);
|
|
3070
3142
|
};
|
|
3071
3143
|
|
|
3072
3144
|
var SPEC_CHAR_RE = /[|\\{}()[\]^$+?.]/g;
|
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.9.
|
|
4
|
+
"version": "2.9.36-beta",
|
|
5
5
|
"dataDirname": ".whistle",
|
|
6
6
|
"localUIHost": "local.whistlejs.com",
|
|
7
7
|
"port": 8899,
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"safe-buffer": "^5.1.2",
|
|
60
60
|
"set-global-proxy": "^0.1.7",
|
|
61
61
|
"sni": "1.0.0",
|
|
62
|
-
"sockx": "^0.2.
|
|
62
|
+
"sockx": "^0.2.1",
|
|
63
63
|
"starting": "^8.0.1",
|
|
64
64
|
"weinre2": "^1.3.2",
|
|
65
65
|
"ws-parser": "^0.6.2",
|