isomorfeus-transport 2.0.6 → 2.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,203 +1,203 @@
1
- 'use strict';
2
-
3
- const { tokenChars } = require('./validation');
4
-
5
- /**
6
- * Adds an offer to the map of extension offers or a parameter to the map of
7
- * parameters.
8
- *
9
- * @param {Object} dest The map of extension offers or parameters
10
- * @param {String} name The extension or parameter name
11
- * @param {(Object|Boolean|String)} elem The extension parameters or the
12
- * parameter value
13
- * @private
14
- */
15
- function push(dest, name, elem) {
16
- if (dest[name] === undefined) dest[name] = [elem];
17
- else dest[name].push(elem);
18
- }
19
-
20
- /**
21
- * Parses the `Sec-WebSocket-Extensions` header into an object.
22
- *
23
- * @param {String} header The field value of the header
24
- * @return {Object} The parsed object
25
- * @public
26
- */
27
- function parse(header) {
28
- const offers = Object.create(null);
29
- let params = Object.create(null);
30
- let mustUnescape = false;
31
- let isEscaping = false;
32
- let inQuotes = false;
33
- let extensionName;
34
- let paramName;
35
- let start = -1;
36
- let code = -1;
37
- let end = -1;
38
- let i = 0;
39
-
40
- for (; i < header.length; i++) {
41
- code = header.charCodeAt(i);
42
-
43
- if (extensionName === undefined) {
44
- if (end === -1 && tokenChars[code] === 1) {
45
- if (start === -1) start = i;
46
- } else if (
47
- i !== 0 &&
48
- (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
49
- ) {
50
- if (end === -1 && start !== -1) end = i;
51
- } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
52
- if (start === -1) {
53
- throw new SyntaxError(`Unexpected character at index ${i}`);
54
- }
55
-
56
- if (end === -1) end = i;
57
- const name = header.slice(start, end);
58
- if (code === 0x2c) {
59
- push(offers, name, params);
60
- params = Object.create(null);
61
- } else {
62
- extensionName = name;
63
- }
64
-
65
- start = end = -1;
66
- } else {
67
- throw new SyntaxError(`Unexpected character at index ${i}`);
68
- }
69
- } else if (paramName === undefined) {
70
- if (end === -1 && tokenChars[code] === 1) {
71
- if (start === -1) start = i;
72
- } else if (code === 0x20 || code === 0x09) {
73
- if (end === -1 && start !== -1) end = i;
74
- } else if (code === 0x3b || code === 0x2c) {
75
- if (start === -1) {
76
- throw new SyntaxError(`Unexpected character at index ${i}`);
77
- }
78
-
79
- if (end === -1) end = i;
80
- push(params, header.slice(start, end), true);
81
- if (code === 0x2c) {
82
- push(offers, extensionName, params);
83
- params = Object.create(null);
84
- extensionName = undefined;
85
- }
86
-
87
- start = end = -1;
88
- } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
89
- paramName = header.slice(start, i);
90
- start = end = -1;
91
- } else {
92
- throw new SyntaxError(`Unexpected character at index ${i}`);
93
- }
94
- } else {
95
- //
96
- // The value of a quoted-string after unescaping must conform to the
97
- // token ABNF, so only token characters are valid.
98
- // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
99
- //
100
- if (isEscaping) {
101
- if (tokenChars[code] !== 1) {
102
- throw new SyntaxError(`Unexpected character at index ${i}`);
103
- }
104
- if (start === -1) start = i;
105
- else if (!mustUnescape) mustUnescape = true;
106
- isEscaping = false;
107
- } else if (inQuotes) {
108
- if (tokenChars[code] === 1) {
109
- if (start === -1) start = i;
110
- } else if (code === 0x22 /* '"' */ && start !== -1) {
111
- inQuotes = false;
112
- end = i;
113
- } else if (code === 0x5c /* '\' */) {
114
- isEscaping = true;
115
- } else {
116
- throw new SyntaxError(`Unexpected character at index ${i}`);
117
- }
118
- } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
119
- inQuotes = true;
120
- } else if (end === -1 && tokenChars[code] === 1) {
121
- if (start === -1) start = i;
122
- } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
123
- if (end === -1) end = i;
124
- } else if (code === 0x3b || code === 0x2c) {
125
- if (start === -1) {
126
- throw new SyntaxError(`Unexpected character at index ${i}`);
127
- }
128
-
129
- if (end === -1) end = i;
130
- let value = header.slice(start, end);
131
- if (mustUnescape) {
132
- value = value.replace(/\\/g, '');
133
- mustUnescape = false;
134
- }
135
- push(params, paramName, value);
136
- if (code === 0x2c) {
137
- push(offers, extensionName, params);
138
- params = Object.create(null);
139
- extensionName = undefined;
140
- }
141
-
142
- paramName = undefined;
143
- start = end = -1;
144
- } else {
145
- throw new SyntaxError(`Unexpected character at index ${i}`);
146
- }
147
- }
148
- }
149
-
150
- if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
151
- throw new SyntaxError('Unexpected end of input');
152
- }
153
-
154
- if (end === -1) end = i;
155
- const token = header.slice(start, end);
156
- if (extensionName === undefined) {
157
- push(offers, token, params);
158
- } else {
159
- if (paramName === undefined) {
160
- push(params, token, true);
161
- } else if (mustUnescape) {
162
- push(params, paramName, token.replace(/\\/g, ''));
163
- } else {
164
- push(params, paramName, token);
165
- }
166
- push(offers, extensionName, params);
167
- }
168
-
169
- return offers;
170
- }
171
-
172
- /**
173
- * Builds the `Sec-WebSocket-Extensions` header field value.
174
- *
175
- * @param {Object} extensions The map of extensions and parameters to format
176
- * @return {String} A string representing the given object
177
- * @public
178
- */
179
- function format(extensions) {
180
- return Object.keys(extensions)
181
- .map((extension) => {
182
- let configurations = extensions[extension];
183
- if (!Array.isArray(configurations)) configurations = [configurations];
184
- return configurations
185
- .map((params) => {
186
- return [extension]
187
- .concat(
188
- Object.keys(params).map((k) => {
189
- let values = params[k];
190
- if (!Array.isArray(values)) values = [values];
191
- return values
192
- .map((v) => (v === true ? k : `${k}=${v}`))
193
- .join('; ');
194
- })
195
- )
196
- .join('; ');
197
- })
198
- .join(', ');
199
- })
200
- .join(', ');
201
- }
202
-
203
- module.exports = { format, parse };
1
+ 'use strict';
2
+
3
+ const { tokenChars } = require('./validation');
4
+
5
+ /**
6
+ * Adds an offer to the map of extension offers or a parameter to the map of
7
+ * parameters.
8
+ *
9
+ * @param {Object} dest The map of extension offers or parameters
10
+ * @param {String} name The extension or parameter name
11
+ * @param {(Object|Boolean|String)} elem The extension parameters or the
12
+ * parameter value
13
+ * @private
14
+ */
15
+ function push(dest, name, elem) {
16
+ if (dest[name] === undefined) dest[name] = [elem];
17
+ else dest[name].push(elem);
18
+ }
19
+
20
+ /**
21
+ * Parses the `Sec-WebSocket-Extensions` header into an object.
22
+ *
23
+ * @param {String} header The field value of the header
24
+ * @return {Object} The parsed object
25
+ * @public
26
+ */
27
+ function parse(header) {
28
+ const offers = Object.create(null);
29
+ let params = Object.create(null);
30
+ let mustUnescape = false;
31
+ let isEscaping = false;
32
+ let inQuotes = false;
33
+ let extensionName;
34
+ let paramName;
35
+ let start = -1;
36
+ let code = -1;
37
+ let end = -1;
38
+ let i = 0;
39
+
40
+ for (; i < header.length; i++) {
41
+ code = header.charCodeAt(i);
42
+
43
+ if (extensionName === undefined) {
44
+ if (end === -1 && tokenChars[code] === 1) {
45
+ if (start === -1) start = i;
46
+ } else if (
47
+ i !== 0 &&
48
+ (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
49
+ ) {
50
+ if (end === -1 && start !== -1) end = i;
51
+ } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
52
+ if (start === -1) {
53
+ throw new SyntaxError(`Unexpected character at index ${i}`);
54
+ }
55
+
56
+ if (end === -1) end = i;
57
+ const name = header.slice(start, end);
58
+ if (code === 0x2c) {
59
+ push(offers, name, params);
60
+ params = Object.create(null);
61
+ } else {
62
+ extensionName = name;
63
+ }
64
+
65
+ start = end = -1;
66
+ } else {
67
+ throw new SyntaxError(`Unexpected character at index ${i}`);
68
+ }
69
+ } else if (paramName === undefined) {
70
+ if (end === -1 && tokenChars[code] === 1) {
71
+ if (start === -1) start = i;
72
+ } else if (code === 0x20 || code === 0x09) {
73
+ if (end === -1 && start !== -1) end = i;
74
+ } else if (code === 0x3b || code === 0x2c) {
75
+ if (start === -1) {
76
+ throw new SyntaxError(`Unexpected character at index ${i}`);
77
+ }
78
+
79
+ if (end === -1) end = i;
80
+ push(params, header.slice(start, end), true);
81
+ if (code === 0x2c) {
82
+ push(offers, extensionName, params);
83
+ params = Object.create(null);
84
+ extensionName = undefined;
85
+ }
86
+
87
+ start = end = -1;
88
+ } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
89
+ paramName = header.slice(start, i);
90
+ start = end = -1;
91
+ } else {
92
+ throw new SyntaxError(`Unexpected character at index ${i}`);
93
+ }
94
+ } else {
95
+ //
96
+ // The value of a quoted-string after unescaping must conform to the
97
+ // token ABNF, so only token characters are valid.
98
+ // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
99
+ //
100
+ if (isEscaping) {
101
+ if (tokenChars[code] !== 1) {
102
+ throw new SyntaxError(`Unexpected character at index ${i}`);
103
+ }
104
+ if (start === -1) start = i;
105
+ else if (!mustUnescape) mustUnescape = true;
106
+ isEscaping = false;
107
+ } else if (inQuotes) {
108
+ if (tokenChars[code] === 1) {
109
+ if (start === -1) start = i;
110
+ } else if (code === 0x22 /* '"' */ && start !== -1) {
111
+ inQuotes = false;
112
+ end = i;
113
+ } else if (code === 0x5c /* '\' */) {
114
+ isEscaping = true;
115
+ } else {
116
+ throw new SyntaxError(`Unexpected character at index ${i}`);
117
+ }
118
+ } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
119
+ inQuotes = true;
120
+ } else if (end === -1 && tokenChars[code] === 1) {
121
+ if (start === -1) start = i;
122
+ } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
123
+ if (end === -1) end = i;
124
+ } else if (code === 0x3b || code === 0x2c) {
125
+ if (start === -1) {
126
+ throw new SyntaxError(`Unexpected character at index ${i}`);
127
+ }
128
+
129
+ if (end === -1) end = i;
130
+ let value = header.slice(start, end);
131
+ if (mustUnescape) {
132
+ value = value.replace(/\\/g, '');
133
+ mustUnescape = false;
134
+ }
135
+ push(params, paramName, value);
136
+ if (code === 0x2c) {
137
+ push(offers, extensionName, params);
138
+ params = Object.create(null);
139
+ extensionName = undefined;
140
+ }
141
+
142
+ paramName = undefined;
143
+ start = end = -1;
144
+ } else {
145
+ throw new SyntaxError(`Unexpected character at index ${i}`);
146
+ }
147
+ }
148
+ }
149
+
150
+ if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
151
+ throw new SyntaxError('Unexpected end of input');
152
+ }
153
+
154
+ if (end === -1) end = i;
155
+ const token = header.slice(start, end);
156
+ if (extensionName === undefined) {
157
+ push(offers, token, params);
158
+ } else {
159
+ if (paramName === undefined) {
160
+ push(params, token, true);
161
+ } else if (mustUnescape) {
162
+ push(params, paramName, token.replace(/\\/g, ''));
163
+ } else {
164
+ push(params, paramName, token);
165
+ }
166
+ push(offers, extensionName, params);
167
+ }
168
+
169
+ return offers;
170
+ }
171
+
172
+ /**
173
+ * Builds the `Sec-WebSocket-Extensions` header field value.
174
+ *
175
+ * @param {Object} extensions The map of extensions and parameters to format
176
+ * @return {String} A string representing the given object
177
+ * @public
178
+ */
179
+ function format(extensions) {
180
+ return Object.keys(extensions)
181
+ .map((extension) => {
182
+ let configurations = extensions[extension];
183
+ if (!Array.isArray(configurations)) configurations = [configurations];
184
+ return configurations
185
+ .map((params) => {
186
+ return [extension]
187
+ .concat(
188
+ Object.keys(params).map((k) => {
189
+ let values = params[k];
190
+ if (!Array.isArray(values)) values = [values];
191
+ return values
192
+ .map((v) => (v === true ? k : `${k}=${v}`))
193
+ .join('; ');
194
+ })
195
+ )
196
+ .join('; ');
197
+ })
198
+ .join(', ');
199
+ })
200
+ .join(', ');
201
+ }
202
+
203
+ module.exports = { format, parse };
@@ -1,55 +1,55 @@
1
- 'use strict';
2
-
3
- const kDone = Symbol('kDone');
4
- const kRun = Symbol('kRun');
5
-
6
- /**
7
- * A very simple job queue with adjustable concurrency. Adapted from
8
- * https://github.com/STRML/async-limiter
9
- */
10
- class Limiter {
11
- /**
12
- * Creates a new `Limiter`.
13
- *
14
- * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
15
- * to run concurrently
16
- */
17
- constructor(concurrency) {
18
- this[kDone] = () => {
19
- this.pending--;
20
- this[kRun]();
21
- };
22
- this.concurrency = concurrency || Infinity;
23
- this.jobs = [];
24
- this.pending = 0;
25
- }
26
-
27
- /**
28
- * Adds a job to the queue.
29
- *
30
- * @param {Function} job The job to run
31
- * @public
32
- */
33
- add(job) {
34
- this.jobs.push(job);
35
- this[kRun]();
36
- }
37
-
38
- /**
39
- * Removes a job from the queue and runs it if possible.
40
- *
41
- * @private
42
- */
43
- [kRun]() {
44
- if (this.pending === this.concurrency) return;
45
-
46
- if (this.jobs.length) {
47
- const job = this.jobs.shift();
48
-
49
- this.pending++;
50
- job(this[kDone]);
51
- }
52
- }
53
- }
54
-
55
- module.exports = Limiter;
1
+ 'use strict';
2
+
3
+ const kDone = Symbol('kDone');
4
+ const kRun = Symbol('kRun');
5
+
6
+ /**
7
+ * A very simple job queue with adjustable concurrency. Adapted from
8
+ * https://github.com/STRML/async-limiter
9
+ */
10
+ class Limiter {
11
+ /**
12
+ * Creates a new `Limiter`.
13
+ *
14
+ * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
15
+ * to run concurrently
16
+ */
17
+ constructor(concurrency) {
18
+ this[kDone] = () => {
19
+ this.pending--;
20
+ this[kRun]();
21
+ };
22
+ this.concurrency = concurrency || Infinity;
23
+ this.jobs = [];
24
+ this.pending = 0;
25
+ }
26
+
27
+ /**
28
+ * Adds a job to the queue.
29
+ *
30
+ * @param {Function} job The job to run
31
+ * @public
32
+ */
33
+ add(job) {
34
+ this.jobs.push(job);
35
+ this[kRun]();
36
+ }
37
+
38
+ /**
39
+ * Removes a job from the queue and runs it if possible.
40
+ *
41
+ * @private
42
+ */
43
+ [kRun]() {
44
+ if (this.pending === this.concurrency) return;
45
+
46
+ if (this.jobs.length) {
47
+ const job = this.jobs.shift();
48
+
49
+ this.pending++;
50
+ job(this[kDone]);
51
+ }
52
+ }
53
+ }
54
+
55
+ module.exports = Limiter;