update node

This commit is contained in:
olevole
2021-10-17 01:15:13 +03:00
parent 35782af048
commit a268022aca
27 changed files with 795 additions and 1428 deletions

2
node/node_modules/async-limiter/.eslintignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
coverage
.nyc_output

10
node/node_modules/async-limiter/.nycrc generated vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"check-coverage": false,
"lines": 99,
"statements": 99,
"functions": 99,
"branches": 99,
"include": [
"index.js"
]
}

View File

@@ -1,6 +1,8 @@
language: node_js language: node_js
node_js: node_js:
- "6" - "6"
- "8"
- "10"
- "node" - "node"
script: npm run travis script: npm run travis
cache: cache:

View File

@@ -1 +0,0 @@
{"/Users/samuelreed/git/forks/async-throttle/index.js":{"path":"/Users/samuelreed/git/forks/async-throttle/index.js","s":{"1":1,"2":7,"3":1,"4":6,"5":6,"6":6,"7":6,"8":6,"9":6,"10":1,"11":1,"12":3,"13":13,"14":13,"15":13,"16":1,"17":19,"18":1,"19":45,"20":6,"21":39,"22":13,"23":13,"24":13,"25":13,"26":39,"27":18,"28":6,"29":6,"30":1,"31":6,"32":6,"33":6,"34":1,"35":13,"36":13,"37":1},"b":{"1":[1,6],"2":[6,5],"3":[6,5],"4":[6,39],"5":[13,26],"6":[18,21],"7":[6,0]},"f":{"1":7,"2":3,"3":13,"4":19,"5":45,"6":6,"7":13},"fnMap":{"1":{"name":"Queue","line":3,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":24}}},"2":{"name":"(anonymous_2)","line":22,"loc":{"start":{"line":22,"column":24},"end":{"line":22,"column":41}}},"3":{"name":"(anonymous_3)","line":23,"loc":{"start":{"line":23,"column":28},"end":{"line":23,"column":39}}},"4":{"name":"(anonymous_4)","line":31,"loc":{"start":{"line":31,"column":7},"end":{"line":31,"column":18}}},"5":{"name":"(anonymous_5)","line":36,"loc":{"start":{"line":36,"column":23},"end":{"line":36,"column":34}}},"6":{"name":"(anonymous_6)","line":55,"loc":{"start":{"line":55,"column":25},"end":{"line":55,"column":38}}},"7":{"name":"done","line":62,"loc":{"start":{"line":62,"column":0},"end":{"line":62,"column":16}}}},"statementMap":{"1":{"start":{"line":3,"column":0},"end":{"line":14,"column":1}},"2":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"3":{"start":{"line":5,"column":4},"end":{"line":5,"column":30}},"4":{"start":{"line":8,"column":2},"end":{"line":8,"column":26}},"5":{"start":{"line":9,"column":2},"end":{"line":9,"column":53}},"6":{"start":{"line":10,"column":2},"end":{"line":10,"column":19}},"7":{"start":{"line":11,"column":2},"end":{"line":11,"column":17}},"8":{"start":{"line":12,"column":2},"end":{"line":12,"column":16}},"9":{"start":{"line":13,"column":2},"end":{"line":13,"column":31}},"10":{"start":{"line":16,"column":0},"end":{"line":20,"column":2}},"11":{"start":{"line":22,"column":0},"end":{"line":28,"column":3}},"12":{"start":{"line":23,"column":2},"end":{"line":27,"column":4}},"13":{"start":{"line":24,"column":4},"end":{"line":24,"column":75}},"14":{"start":{"line":25,"column":4},"end":{"line":25,"column":16}},"15":{"start":{"line":26,"column":4},"end":{"line":26,"column":24}},"16":{"start":{"line":30,"column":0},"end":{"line":34,"column":3}},"17":{"start":{"line":32,"column":4},"end":{"line":32,"column":43}},"18":{"start":{"line":36,"column":0},"end":{"line":53,"column":2}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":3}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":11}},"21":{"start":{"line":40,"column":2},"end":{"line":45,"column":3}},"22":{"start":{"line":41,"column":4},"end":{"line":41,"column":32}},"23":{"start":{"line":42,"column":4},"end":{"line":42,"column":19}},"24":{"start":{"line":43,"column":4},"end":{"line":43,"column":20}},"25":{"start":{"line":44,"column":4},"end":{"line":44,"column":16}},"26":{"start":{"line":47,"column":2},"end":{"line":52,"column":3}},"27":{"start":{"line":48,"column":4},"end":{"line":51,"column":5}},"28":{"start":{"line":49,"column":6},"end":{"line":49,"column":30}},"29":{"start":{"line":50,"column":6},"end":{"line":50,"column":27}},"30":{"start":{"line":55,"column":0},"end":{"line":60,"column":2}},"31":{"start":{"line":56,"column":2},"end":{"line":59,"column":3}},"32":{"start":{"line":57,"column":4},"end":{"line":57,"column":22}},"33":{"start":{"line":58,"column":4},"end":{"line":58,"column":16}},"34":{"start":{"line":62,"column":0},"end":{"line":65,"column":1}},"35":{"start":{"line":63,"column":2},"end":{"line":63,"column":17}},"36":{"start":{"line":64,"column":2},"end":{"line":64,"column":14}},"37":{"start":{"line":67,"column":0},"end":{"line":67,"column":23}}},"branchMap":{"1":{"line":4,"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":4,"column":2}},{"start":{"line":4,"column":2},"end":{"line":4,"column":2}}]},"2":{"line":8,"type":"binary-expr","locations":[{"start":{"line":8,"column":12},"end":{"line":8,"column":19}},{"start":{"line":8,"column":23},"end":{"line":8,"column":25}}]},"3":{"line":9,"type":"binary-expr","locations":[{"start":{"line":9,"column":21},"end":{"line":9,"column":40}},{"start":{"line":9,"column":44},"end":{"line":9,"column":52}}]},"4":{"line":37,"type":"if","locations":[{"start":{"line":37,"column":2},"end":{"line":37,"column":2}},{"start":{"line":37,"column":2},"end":{"line":37,"column":2}}]},"5":{"line":40,"type":"if","locations":[{"start":{"line":40,"column":2},"end":{"line":40,"column":2}},{"start":{"line":40,"column":2},"end":{"line":40,"column":2}}]},"6":{"line":47,"type":"if","locations":[{"start":{"line":47,"column":2},"end":{"line":47,"column":2}},{"start":{"line":47,"column":2},"end":{"line":47,"column":2}}]},"7":{"line":56,"type":"if","locations":[{"start":{"line":56,"column":2},"end":{"line":56,"column":2}},{"start":{"line":56,"column":2},"end":{"line":56,"column":2}}]}}}}

View File

@@ -1,73 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for async-throttle/</title>
<meta charset="utf-8">
<link rel="stylesheet" href="../prettify.css">
<link rel="stylesheet" href="../base.css">
<style type='text/css'>
div.coverage-summary .sorter {
background-image: url(../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class="header high">
<h1>Code coverage report for <span class="entity">async-throttle/</span></h1>
<h2>
Statements: <span class="metric">100% <small>(37 / 37)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Branches: <span class="metric">92.86% <small>(13 / 14)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Functions: <span class="metric">100% <small>(7 / 7)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Lines: <span class="metric">100% <small>(37 / 37)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Ignored: <span class="metric"><span class="ignore-none">none</span></span> &nbsp;&nbsp;&nbsp;&nbsp;
</h2>
<div class="path"><a href="../index.html">All files</a> &#187; async-throttle/</div>
</div>
<div class="body">
<div class="coverage-summary">
<table>
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file high" data-value="index.js"><a href="index.js.html">index.js</a></td>
<td data-value="100" class="pic high"><span class="cover-fill cover-full" style="width: 100px;"></span><span class="cover-empty" style="width:0px;"></span></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="37" class="abs high">(37&nbsp;/&nbsp;37)</td>
<td data-value="92.86" class="pct high">92.86%</td>
<td data-value="14" class="abs high">(13&nbsp;/&nbsp;14)</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="7" class="abs high">(7&nbsp;/&nbsp;7)</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="37" class="abs high">(37&nbsp;/&nbsp;37)</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="footer">
<div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Mon Sep 11 2017 11:14:14 GMT-0500 (CDT)</div>
</div>
<script src="../prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="../sorter.js"></script>
</body>
</html>

View File

@@ -1,246 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for async-throttle/index.js</title>
<meta charset="utf-8">
<link rel="stylesheet" href="../prettify.css">
<link rel="stylesheet" href="../base.css">
<style type='text/css'>
div.coverage-summary .sorter {
background-image: url(../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class="header high">
<h1>Code coverage report for <span class="entity">async-throttle/index.js</span></h1>
<h2>
Statements: <span class="metric">100% <small>(37 / 37)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Branches: <span class="metric">92.86% <small>(13 / 14)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Functions: <span class="metric">100% <small>(7 / 7)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Lines: <span class="metric">100% <small>(37 / 37)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Ignored: <span class="metric"><span class="ignore-none">none</span></span> &nbsp;&nbsp;&nbsp;&nbsp;
</h2>
<div class="path"><a href="../index.html">All files</a> &#187; <a href="index.html">async-throttle/</a> &#187; index.js</div>
</div>
<div class="body">
<pre><table class="coverage">
<tr><td class="line-count">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68</td><td class="line-coverage"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-yes">7</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-yes">3</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">19</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-yes">45</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">39</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">39</span>
<span class="cline-any cline-yes">18</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-yes">6</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-yes">13</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">'use strict';
&nbsp;
function Queue(options) {
if (!(this instanceof Queue)) {
return new Queue(options);
}
&nbsp;
options = options || {};
this.concurrency = options.concurrency || Infinity;
this.pending = 0;
this.jobs = [];
this.cbs = [];
this._done = done.bind(this);
}
&nbsp;
var arrayAddMethods = [
'push',
'unshift',
'splice'
];
&nbsp;
arrayAddMethods.forEach(function(method) {
Queue.prototype[method] = function() {
var methodResult = Array.prototype[method].apply(this.jobs, arguments);
this._run();
return methodResult;
};
});
&nbsp;
Object.defineProperty(Queue.prototype, 'length', {
get: function() {
return this.pending + this.jobs.length;
}
});
&nbsp;
Queue.prototype._run = function() {
if (this.pending === this.concurrency) {
return;
}
if (this.jobs.length) {
var job = this.jobs.shift();
this.pending++;
job(this._done);
this._run();
}
&nbsp;
if (this.pending === 0) {
while (this.cbs.length !== 0) {
var cb = this.cbs.pop();
process.nextTick(cb);
}
}
};
&nbsp;
Queue.prototype.onDone = function(cb) {
<span class="missing-if-branch" title="else path not taken" >E</span>if (typeof cb === 'function') {
this.cbs.push(cb);
this._run();
}
};
&nbsp;
function done() {
this.pending--;
this._run();
}
&nbsp;
module.exports = Queue;
&nbsp;</pre></td></tr>
</table></pre>
</div>
<div class="footer">
<div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Mon Sep 11 2017 11:14:14 GMT-0500 (CDT)</div>
</div>
<script src="../prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="../sorter.js"></script>
</body>
</html>

View File

@@ -1,182 +0,0 @@
body, html {
margin:0; padding: 0;
}
body {
font-family: Helvetica Neue, Helvetica,Arial;
font-size: 10pt;
}
div.header, div.footer {
background: #eee;
padding: 1em;
}
div.header {
z-index: 100;
position: fixed;
top: 0;
border-bottom: 1px solid #666;
width: 100%;
}
div.footer {
border-top: 1px solid #666;
}
div.body {
margin-top: 10em;
}
div.meta {
font-size: 90%;
text-align: center;
}
h1, h2, h3 {
font-weight: normal;
}
h1 {
font-size: 12pt;
}
h2 {
font-size: 10pt;
}
pre {
font-family: Consolas, Menlo, Monaco, monospace;
margin: 0;
padding: 0;
line-height: 1.3;
font-size: 14px;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
}
div.path { font-size: 110%; }
div.path a:link, div.path a:visited { color: #000; }
table.coverage { border-collapse: collapse; margin:0; padding: 0 }
table.coverage td {
margin: 0;
padding: 0;
color: #111;
vertical-align: top;
}
table.coverage td.line-count {
width: 50px;
text-align: right;
padding-right: 5px;
}
table.coverage td.line-coverage {
color: #777 !important;
text-align: right;
border-left: 1px solid #666;
border-right: 1px solid #666;
}
table.coverage td.text {
}
table.coverage td span.cline-any {
display: inline-block;
padding: 0 5px;
width: 40px;
}
table.coverage td span.cline-neutral {
background: #eee;
}
table.coverage td span.cline-yes {
background: #b5d592;
color: #999;
}
table.coverage td span.cline-no {
background: #fc8c84;
}
.cstat-yes { color: #111; }
.cstat-no { background: #fc8c84; color: #111; }
.fstat-no { background: #ffc520; color: #111 !important; }
.cbranch-no { background: yellow !important; color: #111; }
.cstat-skip { background: #ddd; color: #111; }
.fstat-skip { background: #ddd; color: #111 !important; }
.cbranch-skip { background: #ddd !important; color: #111; }
.missing-if-branch {
display: inline-block;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: black;
color: yellow;
}
.skip-if-branch {
display: none;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: #ccc;
color: white;
}
.missing-if-branch .typ, .skip-if-branch .typ {
color: inherit !important;
}
.entity, .metric { font-weight: bold; }
.metric { display: inline-block; border: 1px solid #333; padding: 0.3em; background: white; }
.metric small { font-size: 80%; font-weight: normal; color: #666; }
div.coverage-summary table { border-collapse: collapse; margin: 3em; font-size: 110%; }
div.coverage-summary td, div.coverage-summary table th { margin: 0; padding: 0.25em 1em; border-top: 1px solid #666; border-bottom: 1px solid #666; }
div.coverage-summary th { text-align: left; border: 1px solid #666; background: #eee; font-weight: normal; }
div.coverage-summary th.file { border-right: none !important; }
div.coverage-summary th.pic { border-left: none !important; text-align: right; }
div.coverage-summary th.pct { border-right: none !important; }
div.coverage-summary th.abs { border-left: none !important; text-align: right; }
div.coverage-summary td.pct { text-align: right; border-left: 1px solid #666; }
div.coverage-summary td.abs { text-align: right; font-size: 90%; color: #444; border-right: 1px solid #666; }
div.coverage-summary td.file { border-left: 1px solid #666; white-space: nowrap; }
div.coverage-summary td.pic { min-width: 120px !important; }
div.coverage-summary a:link { text-decoration: none; color: #000; }
div.coverage-summary a:visited { text-decoration: none; color: #777; }
div.coverage-summary a:hover { text-decoration: underline; }
div.coverage-summary tfoot td { border-top: 1px solid #666; }
div.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
div.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
div.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
.high { background: #b5d592 !important; }
.medium { background: #ffe87c !important; }
.low { background: #fc8c84 !important; }
span.cover-fill, span.cover-empty {
display:inline-block;
border:1px solid #444;
background: white;
height: 12px;
}
span.cover-fill {
background: #ccc;
border-right: 1px solid #444;
}
span.cover-empty {
background: white;
border-left: none;
}
span.cover-full {
border-right: none !important;
}
pre.prettyprint {
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.com { color: #999 !important; }
.ignore-none { color: #999; font-weight: normal; }

View File

@@ -1,73 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for All files</title>
<meta charset="utf-8">
<link rel="stylesheet" href="prettify.css">
<link rel="stylesheet" href="base.css">
<style type='text/css'>
div.coverage-summary .sorter {
background-image: url(sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class="header high">
<h1>Code coverage report for <span class="entity">All files</span></h1>
<h2>
Statements: <span class="metric">100% <small>(37 / 37)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Branches: <span class="metric">92.86% <small>(13 / 14)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Functions: <span class="metric">100% <small>(7 / 7)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Lines: <span class="metric">100% <small>(37 / 37)</small></span> &nbsp;&nbsp;&nbsp;&nbsp;
Ignored: <span class="metric"><span class="ignore-none">none</span></span> &nbsp;&nbsp;&nbsp;&nbsp;
</h2>
<div class="path"></div>
</div>
<div class="body">
<div class="coverage-summary">
<table>
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file high" data-value="async-throttle/"><a href="async-throttle/index.html">async-throttle/</a></td>
<td data-value="100" class="pic high"><span class="cover-fill cover-full" style="width: 100px;"></span><span class="cover-empty" style="width:0px;"></span></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="37" class="abs high">(37&nbsp;/&nbsp;37)</td>
<td data-value="92.86" class="pct high">92.86%</td>
<td data-value="14" class="abs high">(13&nbsp;/&nbsp;14)</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="7" class="abs high">(7&nbsp;/&nbsp;7)</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="37" class="abs high">(37&nbsp;/&nbsp;37)</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="footer">
<div class="meta">Generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Mon Sep 11 2017 11:14:14 GMT-0500 (CDT)</div>
</div>
<script src="prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="sorter.js"></script>
</body>
</html>

View File

@@ -1 +0,0 @@
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

View File

@@ -1,156 +0,0 @@
var addSorting = (function () {
"use strict";
var cols,
currentSort = {
index: 0,
desc: false
};
// returns the summary table element
function getTable() { return document.querySelector('.coverage-summary table'); }
// returns the thead element of the summary table
function getTableHeader() { return getTable().querySelector('thead tr'); }
// returns the tbody element of the summary table
function getTableBody() { return getTable().querySelector('tbody'); }
// returns the th element for nth column
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
// loads all columns
function loadColumns() {
var colNodes = getTableHeader().querySelectorAll('th'),
colNode,
cols = [],
col,
i;
for (i = 0; i < colNodes.length; i += 1) {
colNode = colNodes[i];
col = {
key: colNode.getAttribute('data-col'),
sortable: !colNode.getAttribute('data-nosort'),
type: colNode.getAttribute('data-type') || 'string'
};
cols.push(col);
if (col.sortable) {
col.defaultDescSort = col.type === 'number';
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
}
}
return cols;
}
// attaches a data attribute to every tr element with an object
// of data values keyed by column name
function loadRowData(tableRow) {
var tableCols = tableRow.querySelectorAll('td'),
colNode,
col,
data = {},
i,
val;
for (i = 0; i < tableCols.length; i += 1) {
colNode = tableCols[i];
col = cols[i];
val = colNode.getAttribute('data-value');
if (col.type === 'number') {
val = Number(val);
}
data[col.key] = val;
}
return data;
}
// loads all row data
function loadData() {
var rows = getTableBody().querySelectorAll('tr'),
i;
for (i = 0; i < rows.length; i += 1) {
rows[i].data = loadRowData(rows[i]);
}
}
// sorts the table using the data for the ith column
function sortByIndex(index, desc) {
var key = cols[index].key,
sorter = function (a, b) {
a = a.data[key];
b = b.data[key];
return a < b ? -1 : a > b ? 1 : 0;
},
finalSorter = sorter,
tableBody = document.querySelector('.coverage-summary tbody'),
rowNodes = tableBody.querySelectorAll('tr'),
rows = [],
i;
if (desc) {
finalSorter = function (a, b) {
return -1 * sorter(a, b);
};
}
for (i = 0; i < rowNodes.length; i += 1) {
rows.push(rowNodes[i]);
tableBody.removeChild(rowNodes[i]);
}
rows.sort(finalSorter);
for (i = 0; i < rows.length; i += 1) {
tableBody.appendChild(rows[i]);
}
}
// removes sort indicators for current column being sorted
function removeSortIndicators() {
var col = getNthColumn(currentSort.index),
cls = col.className;
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
col.className = cls;
}
// adds sort indicators for current column being sorted
function addSortIndicators() {
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
}
// adds event listeners for all sorter widgets
function enableUI() {
var i,
el,
ithSorter = function ithSorter(i) {
var col = cols[i];
return function () {
var desc = col.defaultDescSort;
if (currentSort.index === i) {
desc = !currentSort.desc;
}
sortByIndex(i, desc);
removeSortIndicators();
currentSort.index = i;
currentSort.desc = desc;
addSortIndicators();
};
};
for (i =0 ; i < cols.length; i += 1) {
if (cols[i].sortable) {
el = getNthColumn(i).querySelector('.sorter');
if (el.addEventListener) {
el.addEventListener('click', ithSorter(i));
} else {
el.attachEvent('onclick', ithSorter(i));
}
}
}
}
// adds sorting functionality to the UI
return function () {
if (!getTable()) {
return;
}
cols = loadColumns();
loadData(cols);
addSortIndicators();
enableUI();
};
})();
window.addEventListener('load', addSorting);

View File

@@ -1,74 +0,0 @@
TN:
SF:/Users/samuelreed/git/forks/async-throttle/index.js
FN:3,Queue
FN:22,(anonymous_2)
FN:23,(anonymous_3)
FN:31,(anonymous_4)
FN:36,(anonymous_5)
FN:55,(anonymous_6)
FN:62,done
FNF:7
FNH:7
FNDA:7,Queue
FNDA:3,(anonymous_2)
FNDA:13,(anonymous_3)
FNDA:19,(anonymous_4)
FNDA:45,(anonymous_5)
FNDA:6,(anonymous_6)
FNDA:13,done
DA:3,1
DA:4,7
DA:5,1
DA:8,6
DA:9,6
DA:10,6
DA:11,6
DA:12,6
DA:13,6
DA:16,1
DA:22,1
DA:23,3
DA:24,13
DA:25,13
DA:26,13
DA:30,1
DA:32,19
DA:36,1
DA:37,45
DA:38,6
DA:40,39
DA:41,13
DA:42,13
DA:43,13
DA:44,13
DA:47,39
DA:48,18
DA:49,6
DA:50,6
DA:55,1
DA:56,6
DA:57,6
DA:58,6
DA:62,1
DA:63,13
DA:64,13
DA:67,1
LF:37
LH:37
BRDA:4,1,0,1
BRDA:4,1,1,6
BRDA:8,2,0,6
BRDA:8,2,1,5
BRDA:9,3,0,6
BRDA:9,3,1,5
BRDA:37,4,0,6
BRDA:37,4,1,39
BRDA:40,5,0,13
BRDA:40,5,1,26
BRDA:47,6,0,18
BRDA:47,6,1,21
BRDA:56,7,0,6
BRDA:56,7,1,0
BRF:14
BRH:13
end_of_record

View File

@@ -1,45 +1,48 @@
{ {
"_from": "async-limiter@~1.0.0", "_args": [
"_id": "async-limiter@1.0.0", [
"async-limiter@1.0.1",
"/usr/local/www/clonos/node"
]
],
"_from": "async-limiter@1.0.1",
"_id": "async-limiter@1.0.1",
"_inBundle": false, "_inBundle": false,
"_integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "_integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
"_location": "/async-limiter", "_location": "/async-limiter",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"type": "range", "type": "version",
"registry": true, "registry": true,
"raw": "async-limiter@~1.0.0", "raw": "async-limiter@1.0.1",
"name": "async-limiter", "name": "async-limiter",
"escapedName": "async-limiter", "escapedName": "async-limiter",
"rawSpec": "~1.0.0", "rawSpec": "1.0.1",
"saveSpec": null, "saveSpec": null,
"fetchSpec": "~1.0.0" "fetchSpec": "1.0.1"
}, },
"_requiredBy": [ "_requiredBy": [
"/ws" "/ws"
], ],
"_resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "_resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"_shasum": "78faed8c3d074ab81f22b4e985d79e8738f720f8", "_spec": "1.0.1",
"_spec": "async-limiter@~1.0.0", "_where": "/usr/local/www/clonos/node",
"_where": "/usr/home/web/cp/clonos/node/node_modules/ws",
"author": { "author": {
"name": "Samuel Reed" "name": "Samuel Reed"
}, },
"bugs": { "bugs": {
"url": "https://github.com/strml/async-limiter/issues" "url": "https://github.com/strml/async-limiter/issues"
}, },
"bundleDependencies": false,
"dependencies": {}, "dependencies": {},
"deprecated": false,
"description": "asynchronous function queue with adjustable concurrency", "description": "asynchronous function queue with adjustable concurrency",
"devDependencies": { "devDependencies": {
"coveralls": "^2.11.2", "coveralls": "^3.0.3",
"eslint": "^4.6.1", "eslint": "^5.16.0",
"eslint-plugin-mocha": "^4.11.0", "eslint-plugin-mocha": "^5.3.0",
"intelli-espower-loader": "^1.0.1", "intelli-espower-loader": "^1.0.1",
"istanbul": "^0.3.2", "mocha": "^6.1.4",
"mocha": "^3.5.2", "nyc": "^14.1.1",
"power-assert": "^1.4.4" "power-assert": "^1.6.1"
}, },
"homepage": "https://github.com/strml/async-limiter#readme", "homepage": "https://github.com/strml/async-limiter#readme",
"keywords": [ "keywords": [
@@ -59,11 +62,11 @@
"url": "git+https://github.com/strml/async-limiter.git" "url": "git+https://github.com/strml/async-limiter.git"
}, },
"scripts": { "scripts": {
"coverage": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | coveralls", "coverage": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
"example": "node example", "example": "node example",
"lint": "eslint .", "lint": "eslint .",
"test": "mocha --R intelli-espower-loader test/", "test": "mocha --require intelli-espower-loader test/",
"travis": "npm run lint && npm run coverage" "travis": "npm run lint && npm run test"
}, },
"version": "1.0.0" "version": "1.0.1"
} }

View File

@@ -93,7 +93,7 @@ console.time('deflate');
for(let i = 0; i < 30000; ++i) { for(let i = 0; i < 30000; ++i) {
deflate(payload, function (err, buffer) {}); deflate(payload, function (err, buffer) {});
} }
q.onDone(function() { t.onDone(function() {
console.timeEnd('deflate'); console.timeEnd('deflate');
}); });
``` ```
@@ -110,23 +110,23 @@ q.onDone(function() {
### `var t = new Limiter([opts])` ### `var t = new Limiter([opts])`
Constructor. `opts` may contain inital values for: Constructor. `opts` may contain inital values for:
* `q.concurrency` * `t.concurrency`
## Instance methods ## Instance methods
### `q.onDone(fn)` ### `t.onDone(fn)`
`fn` will be called once and only once, when the queue is empty. `fn` will be called once and only once, when the queue is empty.
## Instance methods mixed in from `Array` ## Instance methods mixed in from `Array`
Mozilla has docs on how these methods work [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Mozilla has docs on how these methods work [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).
### `q.push(element1, ..., elementN)` ### `t.push(element1, ..., elementN)`
### `q.unshift(element1, ..., elementN)` ### `t.unshift(element1, ..., elementN)`
### `q.splice(index , howMany[, element1[, ...[, elementN]]])` ### `t.splice(index , howMany[, element1[, ...[, elementN]]])`
## Properties ## Properties
### `q.concurrency` ### `t.concurrency`
Max number of jobs the queue should process concurrently, defaults to `Infinity`. Max number of jobs the queue should process concurrently, defaults to `Infinity`.
### `q.length` ### `t.length`
Jobs pending + jobs to process (readonly). Jobs pending + jobs to process (readonly).

152
node/node_modules/ws/README.md generated vendored
View File

@@ -1,12 +1,12 @@
# ws: a Node.js WebSocket library # ws: a Node.js WebSocket library
[![Version npm](https://img.shields.io/npm/v/ws.svg)](https://www.npmjs.com/package/ws) [![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws)
[![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg)](https://travis-ci.org/websockets/ws) [![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg?logo=travis)](https://travis-ci.org/websockets/ws)
[![Windows Build](https://ci.appveyor.com/api/projects/status/github/websockets/ws?branch=master&svg=true)](https://ci.appveyor.com/project/lpinca/ws) [![Windows Build](https://img.shields.io/appveyor/ci/lpinca/ws/master.svg?logo=appveyor)](https://ci.appveyor.com/project/lpinca/ws)
[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/r/websockets/ws?branch=master) [![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/github/websockets/ws)
ws is a simple to use, blazing fast, and thoroughly tested WebSocket client ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and
and server implementation. server implementation.
Passes the quite extensive Autobahn test suite: [server][server-report], Passes the quite extensive Autobahn test suite: [server][server-report],
[client][client-report]. [client][client-report].
@@ -14,44 +14,45 @@ Passes the quite extensive Autobahn test suite: [server][server-report],
**Note**: This module does not work in the browser. The client in the docs is a **Note**: This module does not work in the browser. The client in the docs is a
reference to a back end with the role of a client in the WebSocket reference to a back end with the role of a client in the WebSocket
communication. Browser clients must use the native communication. Browser clients must use the native
[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) object. [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
To make the same code work seamlessly on Node.js and the browser, you can use object. To make the same code work seamlessly on Node.js and the browser, you
one of the many wrappers available on npm, like can use one of the many wrappers available on npm, like
[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws). [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
## Table of Contents ## Table of Contents
* [Protocol support](#protocol-support) - [Protocol support](#protocol-support)
* [Installing](#installing) - [Installing](#installing)
+ [Opt-in for performance and spec compliance](#opt-in-for-performance-and-spec-compliance) - [Opt-in for performance and spec compliance](#opt-in-for-performance-and-spec-compliance)
* [API docs](#api-docs) - [API docs](#api-docs)
* [WebSocket compression](#websocket-compression) - [WebSocket compression](#websocket-compression)
* [Usage examples](#usage-examples) - [Usage examples](#usage-examples)
+ [Sending and receiving text data](#sending-and-receiving-text-data) - [Sending and receiving text data](#sending-and-receiving-text-data)
+ [Sending binary data](#sending-binary-data) - [Sending binary data](#sending-binary-data)
+ [Simple server](#simple-server) - [Simple server](#simple-server)
+ [External HTTP/S server](#external-https-server) - [External HTTP/S server](#external-https-server)
+ [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server) - [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server)
+ [Server broadcast](#server-broadcast) - [Server broadcast](#server-broadcast)
+ [echo.websocket.org demo](#echowebsocketorg-demo) - [echo.websocket.org demo](#echowebsocketorg-demo)
+ [Other examples](#other-examples) - [Other examples](#other-examples)
* [Error handling best practices](#error-handling-best-practices) - [Error handling best practices](#error-handling-best-practices)
* [FAQ](#faq) - [FAQ](#faq)
+ [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client) - [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
+ [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections) - [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
+ [How to connect via a proxy?](#how-to-connect-via-a-proxy) - [How to connect via a proxy?](#how-to-connect-via-a-proxy)
* [Changelog](#changelog) - [Changelog](#changelog)
* [License](#license) - [License](#license)
## Protocol support ## Protocol support
* **HyBi drafts 07-12** (Use the option `protocolVersion: 8`) - **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
* **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`) - **HyBi drafts 13-17** (Current default, alternatively option
`protocolVersion: 13`)
## Installing ## Installing
``` ```
npm install --save ws npm install ws
``` ```
### Opt-in for performance and spec compliance ### Opt-in for performance and spec compliance
@@ -64,8 +65,8 @@ necessarily need to have a C++ compiler installed on your machine.
- `npm install --save-optional bufferutil`: Allows to efficiently perform - `npm install --save-optional bufferutil`: Allows to efficiently perform
operations such as masking and unmasking the data payload of the WebSocket operations such as masking and unmasking the data payload of the WebSocket
frames. frames.
- `npm install --save-optional utf-8-validate`: Allows to efficiently check - `npm install --save-optional utf-8-validate`: Allows to efficiently check if a
if a message contains valid UTF-8 as required by the spec. message contains valid UTF-8 as required by the spec.
## API docs ## API docs
@@ -73,21 +74,20 @@ See [`/doc/ws.md`](./doc/ws.md) for Node.js-like docs for the ws classes.
## WebSocket compression ## WebSocket compression
ws supports the [permessage-deflate extension][permessage-deflate] which ws supports the [permessage-deflate extension][permessage-deflate] which enables
enables the client and server to negotiate a compression algorithm and its the client and server to negotiate a compression algorithm and its parameters,
parameters, and then selectively apply it to the data payloads of each and then selectively apply it to the data payloads of each WebSocket message.
WebSocket message.
The extension is disabled by default on the server and enabled by default on The extension is disabled by default on the server and enabled by default on the
the client. It adds a significant overhead in terms of performance and memory client. It adds a significant overhead in terms of performance and memory
consumption so we suggest to enable it only if it is really needed. consumption so we suggest to enable it only if it is really needed.
Note that Node.js has a variety of issues with high-performance compression, Note that Node.js has a variety of issues with high-performance compression,
where increased concurrency, especially on Linux, can lead to where increased concurrency, especially on Linux, can lead to [catastrophic
[catastrophic memory fragmentation][node-zlib-bug] and slow performance. memory fragmentation][node-zlib-bug] and slow performance. If you intend to use
If you intend to use permessage-deflate in production, it is worthwhile to set permessage-deflate in production, it is worthwhile to set up a test
up a test representative of your workload and ensure Node.js/zlib will handle representative of your workload and ensure Node.js/zlib will handle it with
it with acceptable performance and memory usage. acceptable performance and memory usage.
Tuning of permessage-deflate can be done via the options defined below. You can Tuning of permessage-deflate can be done via the options defined below. You can
also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
@@ -101,10 +101,11 @@ const WebSocket = require('ws');
const wss = new WebSocket.Server({ const wss = new WebSocket.Server({
port: 8080, port: 8080,
perMessageDeflate: { perMessageDeflate: {
zlibDeflateOptions: { // See zlib defaults. zlibDeflateOptions: {
// See zlib defaults.
chunkSize: 1024, chunkSize: 1024,
memLevel: 7, memLevel: 7,
level: 3, level: 3
}, },
zlibInflateOptions: { zlibInflateOptions: {
chunkSize: 10 * 1024 chunkSize: 10 * 1024
@@ -112,11 +113,10 @@ const wss = new WebSocket.Server({
// Other options settable: // Other options settable:
clientNoContextTakeover: true, // Defaults to negotiated value. clientNoContextTakeover: true, // Defaults to negotiated value.
serverNoContextTakeover: true, // Defaults to negotiated value. serverNoContextTakeover: true, // Defaults to negotiated value.
clientMaxWindowBits: 10, // Defaults to negotiated value.
serverMaxWindowBits: 10, // Defaults to negotiated value. serverMaxWindowBits: 10, // Defaults to negotiated value.
// Below options specified as default values. // Below options specified as default values.
concurrencyLimit: 10, // Limits zlib concurrency for perf. concurrencyLimit: 10, // Limits zlib concurrency for perf.
threshold: 1024, // Size (in bytes) below which messages threshold: 1024 // Size (in bytes) below which messages
// should not be compressed. // should not be compressed.
} }
}); });
@@ -326,8 +326,11 @@ ws.send('something', function ack(error) {
// Immediate errors can also be handled with `try...catch`, but **note** that // Immediate errors can also be handled with `try...catch`, but **note** that
// since sends are inherently asynchronous, socket write failures will *not* be // since sends are inherently asynchronous, socket write failures will *not* be
// captured when this technique is used. // captured when this technique is used.
try { ws.send('something'); } try {
catch (e) { /* handle error */ } ws.send('something');
} catch (e) {
/* handle error */
}
``` ```
## FAQ ## FAQ
@@ -357,8 +360,8 @@ wss.on('connection', function connection(ws, req) {
### How to detect and close broken connections? ### How to detect and close broken connections?
Sometimes the link between the server and the client can be interrupted in a Sometimes the link between the server and the client can be interrupted in a way
way that keeps both the server and the client unaware of the broken state of the that keeps both the server and the client unaware of the broken state of the
connection (e.g. when pulling the cord). connection (e.g. when pulling the cord).
In these cases ping messages can be used as a means to verify that the remote In these cases ping messages can be used as a means to verify that the remote
@@ -367,14 +370,14 @@ endpoint is still responsive.
```js ```js
const WebSocket = require('ws'); const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
function noop() {} function noop() {}
function heartbeat() { function heartbeat() {
this.isAlive = true; this.isAlive = true;
} }
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) { wss.on('connection', function connection(ws) {
ws.isAlive = true; ws.isAlive = true;
ws.on('pong', heartbeat); ws.on('pong', heartbeat);
@@ -390,8 +393,35 @@ const interval = setInterval(function ping() {
}, 30000); }, 30000);
``` ```
Pong messages are automatically sent in response to ping messages as required Pong messages are automatically sent in response to ping messages as required by
by the spec. the spec.
Just like the server example above your clients might as well lose connection
without knowing it. You might want to add a ping listener on your clients to
prevent that. A simple implementation would be:
```js
const WebSocket = require('ws');
function heartbeat() {
clearTimeout(this.pingTimeout);
// Use `WebSocket#terminate()` and not `WebSocket#close()`. Delay should be
// equal to the interval at which your server sends out pings plus a
// conservative assumption of the latency.
this.pingTimeout = setTimeout(() => {
this.terminate();
}, 30000 + 1000);
}
const client = new WebSocket('wss://echo.websocket.org/');
client.on('open', heartbeat);
client.on('ping', heartbeat);
client.on('close', function clear() {
clearTimeout(this.pingTimeout);
});
```
### How to connect via a proxy? ### How to connect via a proxy?
@@ -413,5 +443,7 @@ We're using the GitHub [releases][changelog] for changelog entries.
[permessage-deflate]: https://tools.ietf.org/html/rfc7692 [permessage-deflate]: https://tools.ietf.org/html/rfc7692
[changelog]: https://github.com/websockets/ws/releases [changelog]: https://github.com/websockets/ws/releases
[node-zlib-bug]: https://github.com/nodejs/node/issues/8871 [node-zlib-bug]: https://github.com/nodejs/node/issues/8871
[node-zlib-deflaterawdocs]: https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options [node-zlib-deflaterawdocs]:
[ws-server-options]: https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
[ws-server-options]:
https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback

View File

@@ -1,5 +1,7 @@
'use strict'; 'use strict';
const { EMPTY_BUFFER } = require('./constants');
/** /**
* Merges an array of buffers into a new buffer. * Merges an array of buffers into a new buffer.
* *
@@ -9,6 +11,9 @@
* @public * @public
*/ */
function concat(list, totalLength) { function concat(list, totalLength) {
if (list.length === 0) return EMPTY_BUFFER;
if (list.length === 1) return list[0];
const target = Buffer.allocUnsafe(totalLength); const target = Buffer.allocUnsafe(totalLength);
var offset = 0; var offset = 0;
@@ -52,21 +57,88 @@ function _unmask (buffer, mask) {
} }
} }
/**
* Converts a buffer to an `ArrayBuffer`.
*
* @param {Buffer} buf The buffer to convert
* @return {ArrayBuffer} Converted buffer
* @public
*/
function toArrayBuffer(buf) {
if (buf.byteLength === buf.buffer.byteLength) {
return buf.buffer;
}
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
}
/**
* Converts `data` to a `Buffer`.
*
* @param {*} data The data to convert
* @return {Buffer} The buffer
* @throws {TypeError}
* @public
*/
function toBuffer(data) {
toBuffer.readOnly = true;
if (Buffer.isBuffer(data)) return data;
var buf;
if (data instanceof ArrayBuffer) {
buf = Buffer.from(data);
} else if (ArrayBuffer.isView(data)) {
buf = viewToBuffer(data);
} else {
buf = Buffer.from(data);
toBuffer.readOnly = false;
}
return buf;
}
/**
* Converts an `ArrayBuffer` view into a buffer.
*
* @param {(DataView|TypedArray)} view The view to convert
* @return {Buffer} Converted view
* @private
*/
function viewToBuffer(view) {
const buf = Buffer.from(view.buffer);
if (view.byteLength !== view.buffer.byteLength) {
return buf.slice(view.byteOffset, view.byteOffset + view.byteLength);
}
return buf;
}
try { try {
const bufferUtil = require('bufferutil'); const bufferUtil = require('bufferutil');
const bu = bufferUtil.BufferUtil || bufferUtil; const bu = bufferUtil.BufferUtil || bufferUtil;
module.exports = { module.exports = {
concat,
mask(source, mask, output, offset, length) { mask(source, mask, output, offset, length) {
if (length < 48) _mask(source, mask, output, offset, length); if (length < 48) _mask(source, mask, output, offset, length);
else bu.mask(source, mask, output, offset, length); else bu.mask(source, mask, output, offset, length);
}, },
toArrayBuffer,
toBuffer,
unmask(buffer, mask) { unmask(buffer, mask) {
if (buffer.length < 32) _unmask(buffer, mask); if (buffer.length < 32) _unmask(buffer, mask);
else bu.unmask(buffer, mask); else bu.unmask(buffer, mask);
}, }
concat
}; };
} catch (e) /* istanbul ignore next */ { } catch (e) /* istanbul ignore next */ {
module.exports = { concat, mask: _mask, unmask: _unmask }; module.exports = {
concat,
mask: _mask,
toArrayBuffer,
toBuffer,
unmask: _unmask
};
} }

View File

@@ -11,6 +11,7 @@
// tokenChars[34] === 0 // '"' // tokenChars[34] === 0 // '"'
// ... // ...
// //
// prettier-ignore
const tokenChars = [ const tokenChars = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
@@ -195,17 +196,27 @@ function parse (header) {
* @public * @public
*/ */
function format(extensions) { function format(extensions) {
return Object.keys(extensions).map((extension) => { return Object.keys(extensions)
.map((extension) => {
var configurations = extensions[extension]; var configurations = extensions[extension];
if (!Array.isArray(configurations)) configurations = [configurations]; if (!Array.isArray(configurations)) configurations = [configurations];
return configurations.map((params) => { return configurations
return [extension].concat(Object.keys(params).map((k) => { .map((params) => {
return [extension]
.concat(
Object.keys(params).map((k) => {
var values = params[k]; var values = params[k];
if (!Array.isArray(values)) values = [values]; if (!Array.isArray(values)) values = [values];
return values.map((v) => v === true ? k : `${k}=${v}`).join('; '); return values
})).join('; '); .map((v) => (v === true ? k : `${k}=${v}`))
}).join(', '); .join('; ');
}).join(', '); })
)
.join('; ');
})
.join(', ');
})
.join(', ');
} }
module.exports = { format, parse }; module.exports = { format, parse };

View File

@@ -4,14 +4,12 @@ const Limiter = require('async-limiter');
const zlib = require('zlib'); const zlib = require('zlib');
const bufferUtil = require('./buffer-util'); const bufferUtil = require('./buffer-util');
const constants = require('./constants'); const { kStatusCode, NOOP } = require('./constants');
const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
const EMPTY_BLOCK = Buffer.from([0x00]); const EMPTY_BLOCK = Buffer.from([0x00]);
const kPerMessageDeflate = Symbol('permessage-deflate'); const kPerMessageDeflate = Symbol('permessage-deflate');
const kWriteInProgress = Symbol('write-in-progress');
const kPendingClose = Symbol('pending-close');
const kTotalLength = Symbol('total-length'); const kTotalLength = Symbol('total-length');
const kCallback = Symbol('callback'); const kCallback = Symbol('callback');
const kBuffers = Symbol('buffers'); const kBuffers = Symbol('buffers');
@@ -55,9 +53,8 @@ class PerMessageDeflate {
constructor(options, isServer, maxPayload) { constructor(options, isServer, maxPayload) {
this._maxPayload = maxPayload | 0; this._maxPayload = maxPayload | 0;
this._options = options || {}; this._options = options || {};
this._threshold = this._options.threshold !== undefined this._threshold =
? this._options.threshold this._options.threshold !== undefined ? this._options.threshold : 1024;
: 1024;
this._isServer = !!isServer; this._isServer = !!isServer;
this._deflate = null; this._deflate = null;
this._inflate = null; this._inflate = null;
@@ -65,7 +62,8 @@ class PerMessageDeflate {
this.params = null; this.params = null;
if (!zlibLimiter) { if (!zlibLimiter) {
const concurrency = this._options.concurrencyLimit !== undefined const concurrency =
this._options.concurrencyLimit !== undefined
? this._options.concurrencyLimit ? this._options.concurrencyLimit
: 10; : 10;
zlibLimiter = new Limiter({ concurrency }); zlibLimiter = new Limiter({ concurrency });
@@ -130,22 +128,15 @@ class PerMessageDeflate {
*/ */
cleanup() { cleanup() {
if (this._inflate) { if (this._inflate) {
if (this._inflate[kWriteInProgress]) {
this._inflate[kPendingClose] = true;
} else {
this._inflate.close(); this._inflate.close();
this._inflate = null; this._inflate = null;
} }
}
if (this._deflate) { if (this._deflate) {
if (this._deflate[kWriteInProgress]) {
this._deflate[kPendingClose] = true;
} else {
this._deflate.close(); this._deflate.close();
this._deflate = null; this._deflate = null;
} }
} }
}
/** /**
* Accept an extension negotiation offer. * Accept an extension negotiation offer.
@@ -339,7 +330,8 @@ class PerMessageDeflate {
if (!this._inflate) { if (!this._inflate) {
const key = `${endpoint}_max_window_bits`; const key = `${endpoint}_max_window_bits`;
const windowBits = typeof this.params[key] !== 'number' const windowBits =
typeof this.params[key] !== 'number'
? zlib.Z_DEFAULT_WINDOWBITS ? zlib.Z_DEFAULT_WINDOWBITS
: this.params[key]; : this.params[key];
@@ -354,7 +346,6 @@ class PerMessageDeflate {
} }
this._inflate[kCallback] = callback; this._inflate[kCallback] = callback;
this._inflate[kWriteInProgress] = true;
this._inflate.write(data); this._inflate.write(data);
if (fin) this._inflate.write(TRAILER); if (fin) this._inflate.write(TRAILER);
@@ -374,14 +365,10 @@ class PerMessageDeflate {
this._inflate[kTotalLength] this._inflate[kTotalLength]
); );
if ( if (fin && this.params[`${endpoint}_no_context_takeover`]) {
(fin && this.params[`${endpoint}_no_context_takeover`]) ||
this._inflate[kPendingClose]
) {
this._inflate.close(); this._inflate.close();
this._inflate = null; this._inflate = null;
} else { } else {
this._inflate[kWriteInProgress] = false;
this._inflate[kTotalLength] = 0; this._inflate[kTotalLength] = 0;
this._inflate[kBuffers] = []; this._inflate[kBuffers] = [];
} }
@@ -408,7 +395,8 @@ class PerMessageDeflate {
if (!this._deflate) { if (!this._deflate) {
const key = `${endpoint}_max_window_bits`; const key = `${endpoint}_max_window_bits`;
const windowBits = typeof this.params[key] !== 'number' const windowBits =
typeof this.params[key] !== 'number'
? zlib.Z_DEFAULT_WINDOWBITS ? zlib.Z_DEFAULT_WINDOWBITS
: this.params[key]; : this.params[key];
@@ -420,17 +408,27 @@ class PerMessageDeflate {
this._deflate[kBuffers] = []; this._deflate[kBuffers] = [];
// //
// `zlib.DeflateRaw` emits an `'error'` event only when an attempt to use // An `'error'` event is emitted, only on Node.js < 10.0.0, if the
// it is made after it has already been closed. This cannot happen here, // `zlib.DeflateRaw` instance is closed while data is being processed.
// so we only add a listener for the `'data'` event. // This can happen if `PerMessageDeflate#cleanup()` is called at the wrong
// time due to an abnormal WebSocket closure.
// //
this._deflate.on('error', NOOP);
this._deflate.on('data', deflateOnData); this._deflate.on('data', deflateOnData);
} }
this._deflate[kWriteInProgress] = true;
this._deflate.write(data); this._deflate.write(data);
this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
if (!this._deflate) {
//
// This `if` statement is only needed for Node.js < 10.0.0 because as of
// commit https://github.com/nodejs/node/commit/5e3f5164, the flush
// callback is no longer called if the deflate stream is closed while
// data is being processed.
//
return;
}
var data = bufferUtil.concat( var data = bufferUtil.concat(
this._deflate[kBuffers], this._deflate[kBuffers],
this._deflate[kTotalLength] this._deflate[kTotalLength]
@@ -438,14 +436,10 @@ class PerMessageDeflate {
if (fin) data = data.slice(0, data.length - 4); if (fin) data = data.slice(0, data.length - 4);
if ( if (fin && this.params[`${endpoint}_no_context_takeover`]) {
(fin && this.params[`${endpoint}_no_context_takeover`]) ||
this._deflate[kPendingClose]
) {
this._deflate.close(); this._deflate.close();
this._deflate = null; this._deflate = null;
} else { } else {
this._deflate[kWriteInProgress] = false;
this._deflate[kTotalLength] = 0; this._deflate[kTotalLength] = 0;
this._deflate[kBuffers] = []; this._deflate[kBuffers] = [];
} }
@@ -486,7 +480,7 @@ function inflateOnData (chunk) {
} }
this[kError] = new RangeError('Max payload size exceeded'); this[kError] = new RangeError('Max payload size exceeded');
this[kError][constants.kStatusCode] = 1009; this[kError][kStatusCode] = 1009;
this.removeListener('data', inflateOnData); this.removeListener('data', inflateOnData);
this.reset(); this.reset();
} }
@@ -503,6 +497,6 @@ function inflateOnError (err) {
// closed when an error is emitted. // closed when an error is emitted.
// //
this[kPerMessageDeflate]._inflate = null; this[kPerMessageDeflate]._inflate = null;
err[constants.kStatusCode] = 1007; err[kStatusCode] = 1007;
this[kCallback](err); this[kCallback](err);
} }

83
node/node_modules/ws/lib/receiver.js generated vendored
View File

@@ -1,11 +1,16 @@
'use strict'; 'use strict';
const stream = require('stream'); const { Writable } = require('stream');
const PerMessageDeflate = require('./permessage-deflate'); const PerMessageDeflate = require('./permessage-deflate');
const bufferUtil = require('./buffer-util'); const {
const validation = require('./validation'); BINARY_TYPES,
const constants = require('./constants'); EMPTY_BUFFER,
kStatusCode,
kWebSocket
} = require('./constants');
const { concat, toArrayBuffer, unmask } = require('./buffer-util');
const { isValidStatusCode, isValidUTF8 } = require('./validation');
const GET_INFO = 0; const GET_INFO = 0;
const GET_PAYLOAD_LENGTH_16 = 1; const GET_PAYLOAD_LENGTH_16 = 1;
@@ -19,7 +24,7 @@ const INFLATING = 5;
* *
* @extends stream.Writable * @extends stream.Writable
*/ */
class Receiver extends stream.Writable { class Receiver extends Writable {
/** /**
* Creates a Receiver instance. * Creates a Receiver instance.
* *
@@ -30,8 +35,8 @@ class Receiver extends stream.Writable {
constructor(binaryType, extensions, maxPayload) { constructor(binaryType, extensions, maxPayload) {
super(); super();
this._binaryType = binaryType || constants.BINARY_TYPES[0]; this._binaryType = binaryType || BINARY_TYPES[0];
this[constants.kWebSocket] = undefined; this[kWebSocket] = undefined;
this._extensions = extensions || {}; this._extensions = extensions || {};
this._maxPayload = maxPayload | 0; this._maxPayload = maxPayload | 0;
@@ -62,7 +67,7 @@ class Receiver extends stream.Writable {
* @param {Function} cb Callback * @param {Function} cb Callback
*/ */
_write(chunk, encoding, cb) { _write(chunk, encoding, cb) {
if (this._opcode === 0x08) return cb(); if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
this._bufferedBytes += chunk.length; this._bufferedBytes += chunk.length;
this._buffers.push(chunk); this._buffers.push(chunk);
@@ -132,7 +137,8 @@ class Receiver extends stream.Writable {
case GET_DATA: case GET_DATA:
err = this.getData(cb); err = this.getData(cb);
break; break;
default: // `INFLATING` default:
// `INFLATING`
this._loop = false; this._loop = false;
return; return;
} }
@@ -314,7 +320,7 @@ class Receiver extends stream.Writable {
* @private * @private
*/ */
getData(cb) { getData(cb) {
var data = constants.EMPTY_BUFFER; var data = EMPTY_BUFFER;
if (this._payloadLength) { if (this._payloadLength) {
if (this._bufferedBytes < this._payloadLength) { if (this._bufferedBytes < this._payloadLength) {
@@ -323,7 +329,7 @@ class Receiver extends stream.Writable {
} }
data = this.consume(this._payloadLength); data = this.consume(this._payloadLength);
if (this._masked) bufferUtil.unmask(data, this._mask); if (this._masked) unmask(data, this._mask);
} }
if (this._opcode > 0x07) return this.controlMessage(data); if (this._opcode > 0x07) return this.controlMessage(data);
@@ -362,7 +368,9 @@ class Receiver extends stream.Writable {
if (buf.length) { if (buf.length) {
this._messageLength += buf.length; this._messageLength += buf.length;
if (this._messageLength > this._maxPayload && this._maxPayload > 0) { if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
return cb(error(RangeError, 'Max payload size exceeded', false, 1009)); return cb(
error(RangeError, 'Max payload size exceeded', false, 1009)
);
} }
this._fragments.push(buf); this._fragments.push(buf);
@@ -395,18 +403,18 @@ class Receiver extends stream.Writable {
var data; var data;
if (this._binaryType === 'nodebuffer') { if (this._binaryType === 'nodebuffer') {
data = toBuffer(fragments, messageLength); data = concat(fragments, messageLength);
} else if (this._binaryType === 'arraybuffer') { } else if (this._binaryType === 'arraybuffer') {
data = toArrayBuffer(toBuffer(fragments, messageLength)); data = toArrayBuffer(concat(fragments, messageLength));
} else { } else {
data = fragments; data = fragments;
} }
this.emit('message', data); this.emit('message', data);
} else { } else {
const buf = toBuffer(fragments, messageLength); const buf = concat(fragments, messageLength);
if (!validation.isValidUTF8(buf)) { if (!isValidUTF8(buf)) {
this._loop = false; this._loop = false;
return error(Error, 'invalid UTF-8 sequence', true, 1007); return error(Error, 'invalid UTF-8 sequence', true, 1007);
} }
@@ -437,26 +445,25 @@ class Receiver extends stream.Writable {
} else { } else {
const code = data.readUInt16BE(0); const code = data.readUInt16BE(0);
if (!validation.isValidStatusCode(code)) { if (!isValidStatusCode(code)) {
return error(RangeError, `invalid status code ${code}`, true, 1002); return error(RangeError, `invalid status code ${code}`, true, 1002);
} }
const buf = data.slice(2); const buf = data.slice(2);
if (!validation.isValidUTF8(buf)) { if (!isValidUTF8(buf)) {
return error(Error, 'invalid UTF-8 sequence', true, 1007); return error(Error, 'invalid UTF-8 sequence', true, 1007);
} }
this.emit('conclude', code, buf.toString()); this.emit('conclude', code, buf.toString());
this.end(); this.end();
} }
} else if (this._opcode === 0x09) {
return; this.emit('ping', data);
} else {
this.emit('pong', data);
} }
if (this._opcode === 0x09) this.emit('ping', data);
else this.emit('pong', data);
this._state = GET_INFO; this._state = GET_INFO;
} }
} }
@@ -480,34 +487,6 @@ function error (ErrorCtor, message, prefix, statusCode) {
); );
Error.captureStackTrace(err, error); Error.captureStackTrace(err, error);
err[constants.kStatusCode] = statusCode; err[kStatusCode] = statusCode;
return err; return err;
} }
/**
* Makes a buffer from a list of fragments.
*
* @param {Buffer[]} fragments The list of fragments composing the message
* @param {Number} messageLength The length of the message
* @return {Buffer}
* @private
*/
function toBuffer (fragments, messageLength) {
if (fragments.length === 1) return fragments[0];
if (fragments.length > 1) return bufferUtil.concat(fragments, messageLength);
return constants.EMPTY_BUFFER;
}
/**
* Converts a buffer to an `ArrayBuffer`.
*
* @param {Buffer} The buffer to convert
* @return {ArrayBuffer} Converted buffer
*/
function toArrayBuffer (buf) {
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
return buf.buffer;
}
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
}

143
node/node_modules/ws/lib/sender.js generated vendored
View File

@@ -1,11 +1,11 @@
'use strict'; 'use strict';
const crypto = require('crypto'); const { randomBytes } = require('crypto');
const PerMessageDeflate = require('./permessage-deflate'); const PerMessageDeflate = require('./permessage-deflate');
const bufferUtil = require('./buffer-util'); const { EMPTY_BUFFER } = require('./constants');
const validation = require('./validation'); const { isValidStatusCode } = require('./validation');
const constants = require('./constants'); const { mask: applyMask, toBuffer } = require('./buffer-util');
/** /**
* HyBi Sender implementation. * HyBi Sender implementation.
@@ -43,7 +43,7 @@ class Sender {
* @public * @public
*/ */
static frame(data, options) { static frame(data, options) {
const merge = data.length < 1024 || (options.mask && options.readOnly); const merge = options.mask && options.readOnly;
var offset = options.mask ? 6 : 2; var offset = options.mask ? 6 : 2;
var payloadLength = data.length; var payloadLength = data.length;
@@ -60,6 +60,8 @@ class Sender {
target[0] = options.fin ? options.opcode | 0x80 : options.opcode; target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
if (options.rsv1) target[0] |= 0x40; if (options.rsv1) target[0] |= 0x40;
target[1] = payloadLength;
if (payloadLength === 126) { if (payloadLength === 126) {
target.writeUInt16BE(data.length, 2); target.writeUInt16BE(data.length, 2);
} else if (payloadLength === 127) { } else if (payloadLength === 127) {
@@ -67,30 +69,22 @@ class Sender {
target.writeUInt32BE(data.length, 6); target.writeUInt32BE(data.length, 6);
} }
if (!options.mask) { if (!options.mask) return [target, data];
target[1] = payloadLength;
if (merge) {
data.copy(target, offset);
return [target];
}
return [target, data]; const mask = randomBytes(4);
}
const mask = crypto.randomBytes(4); target[1] |= 0x80;
target[1] = payloadLength | 0x80;
target[offset - 4] = mask[0]; target[offset - 4] = mask[0];
target[offset - 3] = mask[1]; target[offset - 3] = mask[1];
target[offset - 2] = mask[2]; target[offset - 2] = mask[2];
target[offset - 1] = mask[3]; target[offset - 1] = mask[3];
if (merge) { if (merge) {
bufferUtil.mask(data, mask, target, offset, data.length); applyMask(data, mask, target, offset, data.length);
return [target]; return [target];
} }
bufferUtil.mask(data, mask, data, 0, data.length); applyMask(data, mask, data, 0, data.length);
return [target, data]; return [target, data];
} }
@@ -107,8 +101,8 @@ class Sender {
var buf; var buf;
if (code === undefined) { if (code === undefined) {
buf = constants.EMPTY_BUFFER; buf = EMPTY_BUFFER;
} else if (typeof code !== 'number' || !validation.isValidStatusCode(code)) { } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
throw new TypeError('First argument must be a valid error code number'); throw new TypeError('First argument must be a valid error code number');
} else if (data === undefined || data === '') { } else if (data === undefined || data === '') {
buf = Buffer.allocUnsafe(2); buf = Buffer.allocUnsafe(2);
@@ -135,13 +129,16 @@ class Sender {
* @private * @private
*/ */
doClose(data, mask, cb) { doClose(data, mask, cb) {
this.sendFrame(Sender.frame(data, { this.sendFrame(
Sender.frame(data, {
fin: true, fin: true,
rsv1: false, rsv1: false,
opcode: 0x08, opcode: 0x08,
mask, mask,
readOnly: false readOnly: false
}), cb); }),
cb
);
} }
/** /**
@@ -153,23 +150,12 @@ class Sender {
* @public * @public
*/ */
ping(data, mask, cb) { ping(data, mask, cb) {
var readOnly = true; const buf = toBuffer(data);
if (!Buffer.isBuffer(data)) {
if (data instanceof ArrayBuffer) {
data = Buffer.from(data);
} else if (ArrayBuffer.isView(data)) {
data = viewToBuffer(data);
} else {
data = Buffer.from(data);
readOnly = false;
}
}
if (this._deflating) { if (this._deflating) {
this.enqueue([this.doPing, data, mask, readOnly, cb]); this.enqueue([this.doPing, buf, mask, toBuffer.readOnly, cb]);
} else { } else {
this.doPing(data, mask, readOnly, cb); this.doPing(buf, mask, toBuffer.readOnly, cb);
} }
} }
@@ -183,13 +169,16 @@ class Sender {
* @private * @private
*/ */
doPing(data, mask, readOnly, cb) { doPing(data, mask, readOnly, cb) {
this.sendFrame(Sender.frame(data, { this.sendFrame(
Sender.frame(data, {
fin: true, fin: true,
rsv1: false, rsv1: false,
opcode: 0x09, opcode: 0x09,
mask, mask,
readOnly readOnly
}), cb); }),
cb
);
} }
/** /**
@@ -201,23 +190,12 @@ class Sender {
* @public * @public
*/ */
pong(data, mask, cb) { pong(data, mask, cb) {
var readOnly = true; const buf = toBuffer(data);
if (!Buffer.isBuffer(data)) {
if (data instanceof ArrayBuffer) {
data = Buffer.from(data);
} else if (ArrayBuffer.isView(data)) {
data = viewToBuffer(data);
} else {
data = Buffer.from(data);
readOnly = false;
}
}
if (this._deflating) { if (this._deflating) {
this.enqueue([this.doPong, data, mask, readOnly, cb]); this.enqueue([this.doPong, buf, mask, toBuffer.readOnly, cb]);
} else { } else {
this.doPong(data, mask, readOnly, cb); this.doPong(buf, mask, toBuffer.readOnly, cb);
} }
} }
@@ -231,13 +209,16 @@ class Sender {
* @private * @private
*/ */
doPong(data, mask, readOnly, cb) { doPong(data, mask, readOnly, cb) {
this.sendFrame(Sender.frame(data, { this.sendFrame(
Sender.frame(data, {
fin: true, fin: true,
rsv1: false, rsv1: false,
opcode: 0x0a, opcode: 0x0a,
mask, mask,
readOnly readOnly
}), cb); }),
cb
);
} }
/** /**
@@ -253,27 +234,15 @@ class Sender {
* @public * @public
*/ */
send(data, options, cb) { send(data, options, cb) {
const buf = toBuffer(data);
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
var opcode = options.binary ? 2 : 1; var opcode = options.binary ? 2 : 1;
var rsv1 = options.compress; var rsv1 = options.compress;
var readOnly = true;
if (!Buffer.isBuffer(data)) {
if (data instanceof ArrayBuffer) {
data = Buffer.from(data);
} else if (ArrayBuffer.isView(data)) {
data = viewToBuffer(data);
} else {
data = Buffer.from(data);
readOnly = false;
}
}
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
if (this._firstFragment) { if (this._firstFragment) {
this._firstFragment = false; this._firstFragment = false;
if (rsv1 && perMessageDeflate) { if (rsv1 && perMessageDeflate) {
rsv1 = data.length >= perMessageDeflate._threshold; rsv1 = buf.length >= perMessageDeflate._threshold;
} }
this._compress = rsv1; this._compress = rsv1;
} else { } else {
@@ -289,22 +258,25 @@ class Sender {
rsv1, rsv1,
opcode, opcode,
mask: options.mask, mask: options.mask,
readOnly readOnly: toBuffer.readOnly
}; };
if (this._deflating) { if (this._deflating) {
this.enqueue([this.dispatch, data, this._compress, opts, cb]); this.enqueue([this.dispatch, buf, this._compress, opts, cb]);
} else { } else {
this.dispatch(data, this._compress, opts, cb); this.dispatch(buf, this._compress, opts, cb);
} }
} else { } else {
this.sendFrame(Sender.frame(data, { this.sendFrame(
Sender.frame(buf, {
fin: options.fin, fin: options.fin,
rsv1: false, rsv1: false,
opcode, opcode,
mask: options.mask, mask: options.mask,
readOnly readOnly: toBuffer.readOnly
}), cb); }),
cb
);
} }
} }
@@ -332,9 +304,9 @@ class Sender {
this._deflating = true; this._deflating = true;
perMessageDeflate.compress(data, options.fin, (_, buf) => { perMessageDeflate.compress(data, options.fin, (_, buf) => {
this._deflating = false;
options.readOnly = false; options.readOnly = false;
this.sendFrame(Sender.frame(buf, options), cb); this.sendFrame(Sender.frame(buf, options), cb);
this._deflating = false;
this.dequeue(); this.dequeue();
}); });
} }
@@ -373,8 +345,10 @@ class Sender {
*/ */
sendFrame(list, cb) { sendFrame(list, cb) {
if (list.length === 2) { if (list.length === 2) {
this._socket.cork();
this._socket.write(list[0]); this._socket.write(list[0]);
this._socket.write(list[1], cb); this._socket.write(list[1], cb);
this._socket.uncork();
} else { } else {
this._socket.write(list[0], cb); this._socket.write(list[0], cb);
} }
@@ -382,20 +356,3 @@ class Sender {
} }
module.exports = Sender; module.exports = Sender;
/**
* Converts an `ArrayBuffer` view into a buffer.
*
* @param {(DataView|TypedArray)} view The view to convert
* @return {Buffer} Converted view
* @private
*/
function viewToBuffer (view) {
const buf = Buffer.from(view.buffer);
if (view.byteLength !== view.buffer.byteLength) {
return buf.slice(view.byteOffset, view.byteOffset + view.byteLength);
}
return buf;
}

View File

@@ -3,7 +3,8 @@
try { try {
const isValidUTF8 = require('utf-8-validate'); const isValidUTF8 = require('utf-8-validate');
exports.isValidUTF8 = typeof isValidUTF8 === 'object' exports.isValidUTF8 =
typeof isValidUTF8 === 'object'
? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0 ? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0
: isValidUTF8; : isValidUTF8;
} catch (e) /* istanbul ignore next */ { } catch (e) /* istanbul ignore next */ {

View File

@@ -3,12 +3,13 @@
const EventEmitter = require('events'); const EventEmitter = require('events');
const crypto = require('crypto'); const crypto = require('crypto');
const http = require('http'); const http = require('http');
const url = require('url');
const PerMessageDeflate = require('./permessage-deflate'); const PerMessageDeflate = require('./permessage-deflate');
const extension = require('./extension'); const extension = require('./extension');
const constants = require('./constants');
const WebSocket = require('./websocket'); const WebSocket = require('./websocket');
const { GUID } = require('./constants');
const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
/** /**
* Class representing a WebSocket server. * Class representing a WebSocket server.
@@ -20,22 +21,27 @@ class WebSocketServer extends EventEmitter {
* Create a `WebSocketServer` instance. * Create a `WebSocketServer` instance.
* *
* @param {Object} options Configuration options * @param {Object} options Configuration options
* @param {Number} options.backlog The maximum length of the queue of pending
* connections
* @param {Boolean} options.clientTracking Specifies whether or not to track
* clients
* @param {Function} options.handleProtocols An hook to handle protocols
* @param {String} options.host The hostname where to bind the server * @param {String} options.host The hostname where to bind the server
* @param {Number} options.maxPayload The maximum allowed message size
* @param {Boolean} options.noServer Enable no server mode
* @param {String} options.path Accept only connections matching this path
* @param {(Boolean|Object)} options.perMessageDeflate Enable/disable
* permessage-deflate
* @param {Number} options.port The port where to bind the server * @param {Number} options.port The port where to bind the server
* @param {http.Server} options.server A pre-created HTTP/S server to use * @param {http.Server} options.server A pre-created HTTP/S server to use
* @param {Function} options.verifyClient An hook to reject connections * @param {Function} options.verifyClient An hook to reject connections
* @param {Function} options.handleProtocols An hook to handle protocols
* @param {String} options.path Accept only connections matching this path
* @param {Boolean} options.noServer Enable no server mode
* @param {Boolean} options.clientTracking Specifies whether or not to track clients
* @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
* @param {Number} options.maxPayload The maximum allowed message size
* @param {Function} callback A listener for the `listening` event * @param {Function} callback A listener for the `listening` event
*/ */
constructor(options, callback) { constructor(options, callback) {
super(); super();
options = Object.assign({ options = Object.assign(
{
maxPayload: 100 * 1024 * 1024, maxPayload: 100 * 1024 * 1024,
perMessageDeflate: false, perMessageDeflate: false,
handleProtocols: null, handleProtocols: null,
@@ -47,7 +53,9 @@ class WebSocketServer extends EventEmitter {
host: null, host: null,
path: null, path: null,
port: null port: null
}, options); },
options
);
if (options.port == null && !options.server && !options.noServer) { if (options.port == null && !options.server && !options.noServer) {
throw new TypeError( throw new TypeError(
@@ -65,7 +73,12 @@ class WebSocketServer extends EventEmitter {
}); });
res.end(body); res.end(body);
}); });
this._server.listen(options.port, options.host, options.backlog, callback); this._server.listen(
options.port,
options.host,
options.backlog,
callback
);
} else if (options.server) { } else if (options.server) {
this._server = options.server; this._server = options.server;
} }
@@ -147,8 +160,11 @@ class WebSocketServer extends EventEmitter {
* @public * @public
*/ */
shouldHandle(req) { shouldHandle(req) {
if (this.options.path && url.parse(req.url).pathname !== this.options.path) { if (this.options.path) {
return false; const index = req.url.indexOf('?');
const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
if (pathname !== this.options.path) return false;
} }
return true; return true;
@@ -166,12 +182,19 @@ class WebSocketServer extends EventEmitter {
handleUpgrade(req, socket, head, cb) { handleUpgrade(req, socket, head, cb) {
socket.on('error', socketOnError); socket.on('error', socketOnError);
const key =
req.headers['sec-websocket-key'] !== undefined
? req.headers['sec-websocket-key'].trim()
: false;
const version = +req.headers['sec-websocket-version']; const version = +req.headers['sec-websocket-version'];
const extensions = {}; const extensions = {};
if ( if (
req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket' || req.method !== 'GET' ||
!req.headers['sec-websocket-key'] || (version !== 8 && version !== 13) || req.headers.upgrade.toLowerCase() !== 'websocket' ||
!key ||
!keyRegex.test(key) ||
(version !== 8 && version !== 13) ||
!this.shouldHandle(req) !this.shouldHandle(req)
) { ) {
return abortHandshake(socket, 400); return abortHandshake(socket, 400);
@@ -185,9 +208,7 @@ class WebSocketServer extends EventEmitter {
); );
try { try {
const offers = extension.parse( const offers = extension.parse(req.headers['sec-websocket-extensions']);
req.headers['sec-websocket-extensions']
);
if (offers[PerMessageDeflate.extensionName]) { if (offers[PerMessageDeflate.extensionName]) {
perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
@@ -203,7 +224,8 @@ class WebSocketServer extends EventEmitter {
// //
if (this.options.verifyClient) { if (this.options.verifyClient) {
const info = { const info = {
origin: req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`], origin:
req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
secure: !!(req.connection.authorized || req.connection.encrypted), secure: !!(req.connection.authorized || req.connection.encrypted),
req req
}; };
@@ -214,7 +236,7 @@ class WebSocketServer extends EventEmitter {
return abortHandshake(socket, code || 401, message, headers); return abortHandshake(socket, code || 401, message, headers);
} }
this.completeUpgrade(extensions, req, socket, head, cb); this.completeUpgrade(key, extensions, req, socket, head, cb);
}); });
return; return;
} }
@@ -222,12 +244,13 @@ class WebSocketServer extends EventEmitter {
if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
} }
this.completeUpgrade(extensions, req, socket, head, cb); this.completeUpgrade(key, extensions, req, socket, head, cb);
} }
/** /**
* Upgrade the connection to WebSocket. * Upgrade the connection to WebSocket.
* *
* @param {String} key The value of the `Sec-WebSocket-Key` header
* @param {Object} extensions The accepted extensions * @param {Object} extensions The accepted extensions
* @param {http.IncomingMessage} req The request object * @param {http.IncomingMessage} req The request object
* @param {net.Socket} socket The network socket between the server and client * @param {net.Socket} socket The network socket between the server and client
@@ -235,28 +258,29 @@ class WebSocketServer extends EventEmitter {
* @param {Function} cb Callback * @param {Function} cb Callback
* @private * @private
*/ */
completeUpgrade (extensions, req, socket, head, cb) { completeUpgrade(key, extensions, req, socket, head, cb) {
// //
// Destroy the socket if the client has already sent a FIN packet. // Destroy the socket if the client has already sent a FIN packet.
// //
if (!socket.readable || !socket.writable) return socket.destroy(); if (!socket.readable || !socket.writable) return socket.destroy();
const key = crypto.createHash('sha1') const digest = crypto
.update(req.headers['sec-websocket-key'] + constants.GUID, 'binary') .createHash('sha1')
.update(key + GUID)
.digest('base64'); .digest('base64');
const headers = [ const headers = [
'HTTP/1.1 101 Switching Protocols', 'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket', 'Upgrade: websocket',
'Connection: Upgrade', 'Connection: Upgrade',
`Sec-WebSocket-Accept: ${key}` `Sec-WebSocket-Accept: ${digest}`
]; ];
const ws = new WebSocket(null); const ws = new WebSocket(null);
var protocol = req.headers['sec-websocket-protocol']; var protocol = req.headers['sec-websocket-protocol'];
if (protocol) { if (protocol) {
protocol = protocol.trim().split(/ *, */); protocol = protocol.split(',').map(trim);
// //
// Optionally call external protocol selection handler. // Optionally call external protocol selection handler.
@@ -353,15 +377,20 @@ function socketOnError () {
function abortHandshake(socket, code, message, headers) { function abortHandshake(socket, code, message, headers) {
if (socket.writable) { if (socket.writable) {
message = message || http.STATUS_CODES[code]; message = message || http.STATUS_CODES[code];
headers = Object.assign({ headers = Object.assign(
'Connection': 'close', {
Connection: 'close',
'Content-type': 'text/html', 'Content-type': 'text/html',
'Content-Length': Buffer.byteLength(message) 'Content-Length': Buffer.byteLength(message)
}, headers); },
headers
);
socket.write( socket.write(
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
Object.keys(headers).map(h => `${h}: ${headers[h]}`).join('\r\n') + Object.keys(headers)
.map((h) => `${h}: ${headers[h]}`)
.join('\r\n') +
'\r\n\r\n' + '\r\n\r\n' +
message message
); );
@@ -370,3 +399,15 @@ function abortHandshake (socket, code, message, headers) {
socket.removeListener('error', socketOnError); socket.removeListener('error', socketOnError);
socket.destroy(); socket.destroy();
} }
/**
* Remove whitespace characters from both ends of a string.
*
* @param {String} str The string
* @return {String} A new string representing `str` stripped of whitespace
* characters from both its beginning and end
* @private
*/
function trim(str) {
return str.trim();
}

272
node/node_modules/ws/lib/websocket.js generated vendored
View File

@@ -11,14 +11,20 @@ const url = require('url');
const PerMessageDeflate = require('./permessage-deflate'); const PerMessageDeflate = require('./permessage-deflate');
const EventTarget = require('./event-target'); const EventTarget = require('./event-target');
const extension = require('./extension'); const extension = require('./extension');
const constants = require('./constants');
const Receiver = require('./receiver'); const Receiver = require('./receiver');
const Sender = require('./sender'); const Sender = require('./sender');
const {
BINARY_TYPES,
EMPTY_BUFFER,
GUID,
kStatusCode,
kWebSocket,
NOOP
} = require('./constants');
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
const kWebSocket = constants.kWebSocket;
const protocolVersions = [8, 13]; const protocolVersions = [8, 13];
const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly. const closeTimeout = 30 * 1000;
/** /**
* Class representing a WebSocket. * Class representing a WebSocket.
@@ -39,19 +45,21 @@ class WebSocket extends EventEmitter {
this.readyState = WebSocket.CONNECTING; this.readyState = WebSocket.CONNECTING;
this.protocol = ''; this.protocol = '';
this._binaryType = constants.BINARY_TYPES[0]; this._binaryType = BINARY_TYPES[0];
this._closeFrameReceived = false; this._closeFrameReceived = false;
this._closeFrameSent = false; this._closeFrameSent = false;
this._closeMessage = ''; this._closeMessage = '';
this._closeTimer = null; this._closeTimer = null;
this._closeCode = 1006; this._closeCode = 1006;
this._extensions = {}; this._extensions = {};
this._isServer = true;
this._receiver = null; this._receiver = null;
this._sender = null; this._sender = null;
this._socket = null; this._socket = null;
if (address !== null) { if (address !== null) {
this._isServer = false;
this._redirects = 0;
if (Array.isArray(protocols)) { if (Array.isArray(protocols)) {
protocols = protocols.join(', '); protocols = protocols.join(', ');
} else if (typeof protocols === 'object' && protocols !== null) { } else if (typeof protocols === 'object' && protocols !== null) {
@@ -59,18 +67,29 @@ class WebSocket extends EventEmitter {
protocols = undefined; protocols = undefined;
} }
initAsClient.call(this, address, protocols, options); initAsClient(this, address, protocols, options);
} else {
this._isServer = true;
} }
} }
get CONNECTING () { return WebSocket.CONNECTING; } get CONNECTING() {
get CLOSING () { return WebSocket.CLOSING; } return WebSocket.CONNECTING;
get CLOSED () { return WebSocket.CLOSED; } }
get OPEN () { return WebSocket.OPEN; } get CLOSING() {
return WebSocket.CLOSING;
}
get CLOSED() {
return WebSocket.CLOSED;
}
get OPEN() {
return WebSocket.OPEN;
}
/** /**
* This deviates from the WHATWG interface since ws doesn't support the required * This deviates from the WHATWG interface since ws doesn't support the
* default "blob" type (instead we define a custom "nodebuffer" type). * required default "blob" type (instead we define a custom "nodebuffer"
* type).
* *
* @type {String} * @type {String}
*/ */
@@ -79,7 +98,7 @@ class WebSocket extends EventEmitter {
} }
set binaryType(type) { set binaryType(type) {
if (constants.BINARY_TYPES.indexOf(type) < 0) return; if (!BINARY_TYPES.includes(type)) return;
this._binaryType = type; this._binaryType = type;
@@ -212,21 +231,17 @@ class WebSocket extends EventEmitter {
if (err) return; if (err) return;
this._closeFrameSent = true; this._closeFrameSent = true;
if (this._socket.writable) {
if (this._closeFrameReceived) this._socket.end(); if (this._closeFrameReceived) this._socket.end();
});
// //
// Ensure that the connection is closed even if the closing handshake // Specify a timeout for the closing handshake to complete.
// fails.
// //
this._closeTimer = setTimeout( this._closeTimer = setTimeout(
this._socket.destroy.bind(this._socket), this._socket.destroy.bind(this._socket),
closeTimeout closeTimeout
); );
} }
});
}
/** /**
* Send a ping. * Send a ping.
@@ -257,7 +272,7 @@ class WebSocket extends EventEmitter {
if (typeof data === 'number') data = data.toString(); if (typeof data === 'number') data = data.toString();
if (mask === undefined) mask = !this._isServer; if (mask === undefined) mask = !this._isServer;
this._sender.ping(data || constants.EMPTY_BUFFER, mask, cb); this._sender.ping(data || EMPTY_BUFFER, mask, cb);
} }
/** /**
@@ -289,7 +304,7 @@ class WebSocket extends EventEmitter {
if (typeof data === 'number') data = data.toString(); if (typeof data === 'number') data = data.toString();
if (mask === undefined) mask = !this._isServer; if (mask === undefined) mask = !this._isServer;
this._sender.pong(data || constants.EMPTY_BUFFER, mask, cb); this._sender.pong(data || EMPTY_BUFFER, mask, cb);
} }
/** /**
@@ -322,18 +337,21 @@ class WebSocket extends EventEmitter {
if (typeof data === 'number') data = data.toString(); if (typeof data === 'number') data = data.toString();
const opts = Object.assign({ const opts = Object.assign(
{
binary: typeof data !== 'string', binary: typeof data !== 'string',
mask: !this._isServer, mask: !this._isServer,
compress: true, compress: true,
fin: true fin: true
}, options); },
options
);
if (!this._extensions[PerMessageDeflate.extensionName]) { if (!this._extensions[PerMessageDeflate.extensionName]) {
opts.compress = false; opts.compress = false;
} }
this._sender.send(data || constants.EMPTY_BUFFER, opts, cb); this._sender.send(data || EMPTY_BUFFER, opts, cb);
} }
/** /**
@@ -356,7 +374,7 @@ class WebSocket extends EventEmitter {
} }
readyStates.forEach((readyState, i) => { readyStates.forEach((readyState, i) => {
WebSocket[readyStates[i]] = i; WebSocket[readyState] = i;
}); });
// //
@@ -376,6 +394,8 @@ readyStates.forEach((readyState, i) => {
for (var i = 0; i < listeners.length; i++) { for (var i = 0; i < listeners.length; i++) {
if (listeners[i]._listener) return listeners[i]._listener; if (listeners[i]._listener) return listeners[i]._listener;
} }
return undefined;
}, },
/** /**
* Add a listener for the event. * Add a listener for the event.
@@ -404,22 +424,34 @@ module.exports = WebSocket;
/** /**
* Initialize a WebSocket client. * Initialize a WebSocket client.
* *
* @param {WebSocket} websocket The client to initialize
* @param {(String|url.Url|url.URL)} address The URL to which to connect * @param {(String|url.Url|url.URL)} address The URL to which to connect
* @param {String} protocols The subprotocols * @param {String} protocols The subprotocols
* @param {Object} options Connection options * @param {Object} options Connection options
* @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable
* @param {Number} options.handshakeTimeout Timeout in milliseconds for the handshake request * permessage-deflate
* @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` header * @param {Number} options.handshakeTimeout Timeout in milliseconds for the
* @param {String} options.origin Value of the `Origin` or `Sec-WebSocket-Origin` header * handshake request
* @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version`
* header
* @param {String} options.origin Value of the `Origin` or
* `Sec-WebSocket-Origin` header
* @param {Number} options.maxPayload The maximum allowed message size * @param {Number} options.maxPayload The maximum allowed message size
* @param {Boolean} options.followRedirects Whether or not to follow redirects
* @param {Number} options.maxRedirects The maximum number of redirects allowed
* @private * @private
*/ */
function initAsClient (address, protocols, options) { function initAsClient(websocket, address, protocols, options) {
options = Object.assign({ const opts = Object.assign(
{
protocolVersion: protocolVersions[1], protocolVersion: protocolVersions[1],
maxPayload: 100 * 1024 * 1024,
perMessageDeflate: true, perMessageDeflate: true,
maxPayload: 100 * 1024 * 1024 followRedirects: false,
}, options, { maxRedirects: 10
},
options,
{
createConnection: undefined, createConnection: undefined,
socketPath: undefined, socketPath: undefined,
hostname: undefined, hostname: undefined,
@@ -430,128 +462,162 @@ function initAsClient (address, protocols, options) {
host: undefined, host: undefined,
path: undefined, path: undefined,
port: undefined port: undefined
}); }
);
if (protocolVersions.indexOf(options.protocolVersion) === -1) { if (!protocolVersions.includes(opts.protocolVersion)) {
throw new RangeError( throw new RangeError(
`Unsupported protocol version: ${options.protocolVersion} ` + `Unsupported protocol version: ${opts.protocolVersion} ` +
`(supported versions: ${protocolVersions.join(', ')})` `(supported versions: ${protocolVersions.join(', ')})`
); );
} }
this._isServer = false;
var parsedUrl; var parsedUrl;
if (typeof address === 'object' && address.href !== undefined) { if (typeof address === 'object' && address.href !== undefined) {
parsedUrl = address; parsedUrl = address;
this.url = address.href; websocket.url = address.href;
} else { } else {
parsedUrl = url.parse(address); //
this.url = address; // The WHATWG URL constructor is not available on Node.js < 6.13.0
//
parsedUrl = url.URL ? new url.URL(address) : url.parse(address);
websocket.url = address;
} }
const isUnixSocket = parsedUrl.protocol === 'ws+unix:'; const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) { if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) {
throw new Error(`Invalid URL: ${this.url}`); throw new Error(`Invalid URL: ${websocket.url}`);
} }
const isSecure = parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:'; const isSecure =
parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:';
const defaultPort = isSecure ? 443 : 80;
const key = crypto.randomBytes(16).toString('base64'); const key = crypto.randomBytes(16).toString('base64');
const httpObj = isSecure ? https : http; const get = isSecure ? https.get : http.get;
const path = parsedUrl.search const path = parsedUrl.search
? `${parsedUrl.pathname || '/'}${parsedUrl.search}` ? `${parsedUrl.pathname || '/'}${parsedUrl.search}`
: parsedUrl.pathname || '/'; : parsedUrl.pathname || '/';
var perMessageDeflate; var perMessageDeflate;
options.createConnection = isSecure ? tlsConnect : netConnect; opts.createConnection = isSecure ? tlsConnect : netConnect;
options.port = parsedUrl.port || (isSecure ? 443 : 80); opts.defaultPort = opts.defaultPort || defaultPort;
options.host = parsedUrl.hostname.startsWith('[') opts.port = parsedUrl.port || defaultPort;
opts.host = parsedUrl.hostname.startsWith('[')
? parsedUrl.hostname.slice(1, -1) ? parsedUrl.hostname.slice(1, -1)
: parsedUrl.hostname; : parsedUrl.hostname;
options.headers = Object.assign({ opts.headers = Object.assign(
'Sec-WebSocket-Version': options.protocolVersion, {
'Sec-WebSocket-Version': opts.protocolVersion,
'Sec-WebSocket-Key': key, 'Sec-WebSocket-Key': key,
'Connection': 'Upgrade', Connection: 'Upgrade',
'Upgrade': 'websocket' Upgrade: 'websocket'
}, options.headers); },
options.path = path; opts.headers
if (options.perMessageDeflate) {
perMessageDeflate = new PerMessageDeflate(
options.perMessageDeflate !== true ? options.perMessageDeflate : {},
false,
options.maxPayload
); );
options.headers['Sec-WebSocket-Extensions'] = extension.format({ opts.path = path;
opts.timeout = opts.handshakeTimeout;
if (opts.perMessageDeflate) {
perMessageDeflate = new PerMessageDeflate(
opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
false,
opts.maxPayload
);
opts.headers['Sec-WebSocket-Extensions'] = extension.format({
[PerMessageDeflate.extensionName]: perMessageDeflate.offer() [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
}); });
} }
if (protocols) { if (protocols) {
options.headers['Sec-WebSocket-Protocol'] = protocols; opts.headers['Sec-WebSocket-Protocol'] = protocols;
} }
if (options.origin) { if (opts.origin) {
if (options.protocolVersion < 13) { if (opts.protocolVersion < 13) {
options.headers['Sec-WebSocket-Origin'] = options.origin; opts.headers['Sec-WebSocket-Origin'] = opts.origin;
} else { } else {
options.headers.Origin = options.origin; opts.headers.Origin = opts.origin;
} }
} }
if (parsedUrl.auth) { if (parsedUrl.auth) {
options.auth = parsedUrl.auth; opts.auth = parsedUrl.auth;
} else if (parsedUrl.username || parsedUrl.password) { } else if (parsedUrl.username || parsedUrl.password) {
options.auth = `${parsedUrl.username}:${parsedUrl.password}`; opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
} }
if (isUnixSocket) { if (isUnixSocket) {
const parts = path.split(':'); const parts = path.split(':');
options.socketPath = parts[0]; opts.socketPath = parts[0];
options.path = parts[1]; opts.path = parts[1];
} }
var req = this._req = httpObj.get(options); var req = (websocket._req = get(opts));
if (options.handshakeTimeout) { if (opts.timeout) {
req.setTimeout( req.on('timeout', () => {
options.handshakeTimeout, abortHandshake(websocket, req, 'Opening handshake has timed out');
() => abortHandshake(this, req, 'Opening handshake has timed out') });
);
} }
req.on('error', (err) => { req.on('error', (err) => {
if (this._req.aborted) return; if (websocket._req.aborted) return;
req = this._req = null; req = websocket._req = null;
this.readyState = WebSocket.CLOSING; websocket.readyState = WebSocket.CLOSING;
this.emit('error', err); websocket.emit('error', err);
this.emitClose(); websocket.emitClose();
}); });
req.on('response', (res) => { req.on('response', (res) => {
if (this.emit('unexpected-response', req, res)) return; const location = res.headers.location;
const statusCode = res.statusCode;
abortHandshake(this, req, `Unexpected server response: ${res.statusCode}`); if (
location &&
opts.followRedirects &&
statusCode >= 300 &&
statusCode < 400
) {
if (++websocket._redirects > opts.maxRedirects) {
abortHandshake(websocket, req, 'Maximum redirects exceeded');
return;
}
req.abort();
const addr = url.URL
? new url.URL(location, address)
: url.resolve(address, location);
initAsClient(websocket, addr, protocols, options);
} else if (!websocket.emit('unexpected-response', req, res)) {
abortHandshake(
websocket,
req,
`Unexpected server response: ${res.statusCode}`
);
}
}); });
req.on('upgrade', (res, socket, head) => { req.on('upgrade', (res, socket, head) => {
this.emit('upgrade', res); websocket.emit('upgrade', res);
// //
// The user may have closed the connection from a listener of the `upgrade` // The user may have closed the connection from a listener of the `upgrade`
// event. // event.
// //
if (this.readyState !== WebSocket.CONNECTING) return; if (websocket.readyState !== WebSocket.CONNECTING) return;
req = this._req = null; req = websocket._req = null;
const digest = crypto.createHash('sha1') const digest = crypto
.update(key + constants.GUID, 'binary') .createHash('sha1')
.update(key + GUID)
.digest('base64'); .digest('base64');
if (res.headers['sec-websocket-accept'] !== digest) { if (res.headers['sec-websocket-accept'] !== digest) {
abortHandshake(this, socket, 'Invalid Sec-WebSocket-Accept header'); abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
return; return;
} }
@@ -563,16 +629,16 @@ function initAsClient (address, protocols, options) {
protError = 'Server sent a subprotocol but none was requested'; protError = 'Server sent a subprotocol but none was requested';
} else if (protocols && !serverProt) { } else if (protocols && !serverProt) {
protError = 'Server sent no subprotocol'; protError = 'Server sent no subprotocol';
} else if (serverProt && protList.indexOf(serverProt) === -1) { } else if (serverProt && !protList.includes(serverProt)) {
protError = 'Server sent an invalid subprotocol'; protError = 'Server sent an invalid subprotocol';
} }
if (protError) { if (protError) {
abortHandshake(this, socket, protError); abortHandshake(websocket, socket, protError);
return; return;
} }
if (serverProt) this.protocol = serverProt; if (serverProt) websocket.protocol = serverProt;
if (perMessageDeflate) { if (perMessageDeflate) {
try { try {
@@ -581,18 +647,22 @@ function initAsClient (address, protocols, options) {
); );
if (extensions[PerMessageDeflate.extensionName]) { if (extensions[PerMessageDeflate.extensionName]) {
perMessageDeflate.accept( perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
extensions[PerMessageDeflate.extensionName] websocket._extensions[
); PerMessageDeflate.extensionName
this._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; ] = perMessageDeflate;
} }
} catch (err) { } catch (err) {
abortHandshake(this, socket, 'Invalid Sec-WebSocket-Extensions header'); abortHandshake(
websocket,
socket,
'Invalid Sec-WebSocket-Extensions header'
);
return; return;
} }
} }
this.setSocket(socket, head, options.maxPayload); websocket.setSocket(socket, head, opts.maxPayload);
}); });
} }
@@ -695,7 +765,7 @@ function receiverOnError (err) {
websocket._socket.removeListener('data', socketOnData); websocket._socket.removeListener('data', socketOnData);
websocket.readyState = WebSocket.CLOSING; websocket.readyState = WebSocket.CLOSING;
websocket._closeCode = err[constants.kStatusCode]; websocket._closeCode = err[kStatusCode];
websocket.emit('error', err); websocket.emit('error', err);
websocket._socket.destroy(); websocket._socket.destroy();
} }
@@ -728,7 +798,7 @@ function receiverOnMessage (data) {
function receiverOnPing(data) { function receiverOnPing(data) {
const websocket = this[kWebSocket]; const websocket = this[kWebSocket];
websocket.pong(data, !websocket._isServer, constants.NOOP); websocket.pong(data, !websocket._isServer, NOOP);
websocket.emit('ping', data); websocket.emit('ping', data);
} }
@@ -818,10 +888,8 @@ function socketOnError () {
const websocket = this[kWebSocket]; const websocket = this[kWebSocket];
this.removeListener('error', socketOnError); this.removeListener('error', socketOnError);
this.on('error', constants.NOOP); this.on('error', NOOP);
if (websocket) {
websocket.readyState = WebSocket.CLOSING; websocket.readyState = WebSocket.CLOSING;
this.destroy(); this.destroy();
} }
}

54
node/node_modules/ws/package.json generated vendored
View File

@@ -1,27 +1,32 @@
{ {
"_from": "ws@6.1.0", "_args": [
"_id": "ws@6.1.0", [
"ws@6.2.2",
"/usr/local/www/clonos/node"
]
],
"_from": "ws@6.2.2",
"_id": "ws@6.2.2",
"_inBundle": false, "_inBundle": false,
"_integrity": "sha512-H3dGVdGvW2H8bnYpIDc3u3LH8Wue3Qh+Zto6aXXFzvESkTVT6rAfKR6tR/+coaUvxs8yHtmNV0uioBF62ZGSTg==", "_integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
"_location": "/ws", "_location": "/ws",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"type": "version", "type": "version",
"registry": true, "registry": true,
"raw": "ws@6.1.0", "raw": "ws@6.2.2",
"name": "ws", "name": "ws",
"escapedName": "ws", "escapedName": "ws",
"rawSpec": "6.1.0", "rawSpec": "6.2.2",
"saveSpec": null, "saveSpec": null,
"fetchSpec": "6.1.0" "fetchSpec": "6.2.2"
}, },
"_requiredBy": [ "_requiredBy": [
"/" "/"
], ],
"_resolved": "https://registry.npmjs.org/ws/-/ws-6.1.0.tgz", "_resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
"_shasum": "119a9dbf92c54e190ec18d10e871d55c95cf9373", "_spec": "6.2.2",
"_spec": "ws@6.1.0", "_where": "/usr/local/www/clonos/node",
"_where": "/usr/home/web/cp/clonos/node",
"author": { "author": {
"name": "Einar Otto Stangvik", "name": "Einar Otto Stangvik",
"email": "einaros@gmail.com", "email": "einaros@gmail.com",
@@ -31,29 +36,26 @@
"bugs": { "bugs": {
"url": "https://github.com/websockets/ws/issues" "url": "https://github.com/websockets/ws/issues"
}, },
"bundleDependencies": false,
"dependencies": { "dependencies": {
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
}, },
"deprecated": false,
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
"devDependencies": { "devDependencies": {
"benchmark": "~2.1.2", "benchmark": "~2.1.4",
"bufferutil": "~4.0.0", "bufferutil": "~4.0.0",
"eslint": "~5.6.1", "coveralls": "~3.0.3",
"eslint-config-standard": "~12.0.0", "eslint": "~5.15.0",
"eslint-plugin-import": "~2.14.0", "eslint-config-prettier": "~4.1.0",
"eslint-plugin-node": "~7.0.0", "eslint-plugin-prettier": "~3.0.0",
"eslint-plugin-promise": "~4.0.0", "mocha": "~6.0.0",
"eslint-plugin-standard": "~4.0.0", "nyc": "~13.3.0",
"mocha": "~5.2.0", "prettier": "~1.16.1",
"nyc": "~13.0.1",
"utf-8-validate": "~5.0.0" "utf-8-validate": "~5.0.0"
}, },
"files": [ "files": [
"browser.js", "browser.js",
"index.js", "index.js",
"lib" "lib/*.js"
], ],
"homepage": "https://github.com/websockets/ws", "homepage": "https://github.com/websockets/ws",
"keywords": [ "keywords": [
@@ -72,9 +74,9 @@
"url": "git+https://github.com/websockets/ws.git" "url": "git+https://github.com/websockets/ws.git"
}, },
"scripts": { "scripts": {
"integration": "eslint . && mocha test/*.integration.js", "integration": "npm run lint && mocha test/*.integration.js",
"lint": "eslint .", "lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yml}\"",
"test": "eslint . && nyc --reporter=html --reporter=text mocha test/*.test.js" "test": "npm run lint && nyc --reporter=html --reporter=text mocha test/*.test.js"
}, },
"version": "6.1.0" "version": "6.2.2"
} }