opal 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +17 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +1 -0
- data/HACKING.md +47 -26
- data/benchmark/benchmarks +415 -103
- data/benchmark/bm_call_overhead.yml +28 -0
- data/benchmark/run.rb +61 -40
- data/docs/cdp_common.json +3364 -0
- data/docs/cdp_common.md +18 -0
- data/docs/{headless_chrome.md → headless_browsers.md} +31 -12
- data/lib/opal/ast/builder.rb +1 -1
- data/lib/opal/builder.rb +6 -1
- data/lib/opal/builder_processors.rb +5 -3
- data/lib/opal/cache.rb +1 -7
- data/lib/opal/cli_options.rb +72 -58
- data/lib/opal/cli_runners/chrome.rb +47 -9
- data/lib/opal/cli_runners/chrome_cdp_interface.rb +238 -112
- data/lib/opal/cli_runners/compiler.rb +146 -13
- data/lib/opal/cli_runners/deno.rb +32 -0
- data/lib/opal/cli_runners/firefox.rb +350 -0
- data/lib/opal/cli_runners/firefox_cdp_interface.rb +212 -0
- data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.cmd +17 -0
- data/lib/opal/cli_runners/node_modules/.bin/chrome-remote-interface.ps1 +28 -0
- data/lib/opal/cli_runners/node_modules/.package-lock.json +41 -0
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/LICENSE +1 -1
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/README.md +322 -182
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/bin/client.js +99 -114
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/chrome-remote-interface.js +1 -11
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/index.js +16 -11
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/api.js +41 -33
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/chrome.js +224 -214
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/devtools.js +71 -191
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/external-request.js +26 -6
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/protocol.json +20788 -9049
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/lib/websocket-wrapper.js +10 -3
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/package.json +59 -123
- data/lib/opal/cli_runners/node_modules/chrome-remote-interface/webpack.config.js +25 -32
- data/lib/opal/cli_runners/node_modules/commander/History.md +298 -0
- data/lib/opal/cli_runners/node_modules/commander/LICENSE +22 -0
- data/lib/opal/cli_runners/node_modules/commander/Readme.md +217 -61
- data/lib/opal/cli_runners/node_modules/commander/index.js +431 -145
- data/lib/opal/cli_runners/node_modules/commander/package.json +16 -79
- data/lib/opal/cli_runners/node_modules/ws/README.md +334 -98
- data/lib/opal/cli_runners/node_modules/ws/browser.js +8 -0
- data/lib/opal/cli_runners/node_modules/ws/index.js +5 -10
- data/lib/opal/cli_runners/node_modules/ws/lib/buffer-util.js +129 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/constants.js +10 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/event-target.js +184 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/extension.js +223 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/limiter.js +55 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/permessage-deflate.js +518 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/receiver.js +607 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/sender.js +409 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/stream.js +180 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/validation.js +104 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/websocket-server.js +447 -0
- data/lib/opal/cli_runners/node_modules/ws/lib/websocket.js +1195 -0
- data/lib/opal/cli_runners/node_modules/ws/package.json +40 -106
- data/lib/opal/cli_runners/package-lock.json +62 -0
- data/lib/opal/cli_runners/package.json +1 -1
- data/lib/opal/cli_runners.rb +26 -4
- data/lib/opal/nodes/args/prepare_post_args.rb +2 -2
- data/lib/opal/nodes/def.rb +8 -8
- data/lib/opal/nodes/iter.rb +12 -12
- data/lib/opal/nodes/logic.rb +1 -1
- data/lib/opal/nodes/masgn.rb +2 -2
- data/lib/opal/parser/with_ruby_lexer.rb +1 -1
- data/lib/opal/paths.rb +14 -0
- data/lib/opal/rewriter.rb +2 -0
- data/lib/opal/rewriters/forward_args.rb +52 -4
- data/lib/opal/rewriters/targeted_patches.rb +94 -0
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/basic_object.rb +1 -1
- data/opal/corelib/boolean.rb +2 -2
- data/opal/corelib/class.rb +11 -0
- data/opal/corelib/constants.rb +3 -3
- data/opal/corelib/enumerable.rb +4 -0
- data/opal/corelib/enumerator.rb +1 -1
- data/opal/corelib/hash.rb +2 -2
- data/opal/corelib/helpers.rb +1 -1
- data/opal/corelib/kernel.rb +3 -3
- data/opal/corelib/method.rb +1 -1
- data/opal/corelib/module.rb +29 -8
- data/opal/corelib/proc.rb +7 -5
- data/opal/corelib/runtime.js +141 -78
- data/opal/corelib/set.rb +252 -0
- data/opal/corelib/string.rb +2 -1
- data/opal/corelib/time.rb +2 -2
- data/opal/opal.rb +1 -0
- data/opal.gemspec +1 -0
- data/spec/filters/bugs/array.rb +22 -13
- data/spec/filters/bugs/base64.rb +5 -5
- data/spec/filters/bugs/basicobject.rb +16 -8
- data/spec/filters/bugs/bigdecimal.rb +161 -160
- data/spec/filters/bugs/binding.rb +10 -10
- data/spec/filters/bugs/class.rb +8 -8
- data/spec/filters/bugs/complex.rb +2 -1
- data/spec/filters/bugs/date.rb +79 -81
- data/spec/filters/bugs/datetime.rb +29 -29
- data/spec/filters/bugs/delegate.rb +1 -3
- data/spec/filters/bugs/encoding.rb +69 -69
- data/spec/filters/bugs/enumerable.rb +22 -20
- data/spec/filters/bugs/enumerator.rb +88 -85
- data/spec/filters/bugs/exception.rb +46 -40
- data/spec/filters/bugs/file.rb +32 -32
- data/spec/filters/bugs/float.rb +26 -21
- data/spec/filters/bugs/freeze.rb +88 -0
- data/spec/filters/bugs/hash.rb +39 -38
- data/spec/filters/bugs/integer.rb +57 -44
- data/spec/filters/bugs/io.rb +1 -1
- data/spec/filters/bugs/kernel.rb +349 -269
- data/spec/filters/bugs/language.rb +220 -188
- data/spec/filters/bugs/main.rb +5 -3
- data/spec/filters/bugs/marshal.rb +38 -38
- data/spec/filters/bugs/math.rb +2 -1
- data/spec/filters/bugs/method.rb +73 -62
- data/spec/filters/bugs/module.rb +163 -143
- data/spec/filters/bugs/numeric.rb +6 -6
- data/spec/filters/bugs/objectspace.rb +16 -16
- data/spec/filters/bugs/openstruct.rb +1 -1
- data/spec/filters/bugs/pack_unpack.rb +51 -51
- data/spec/filters/bugs/pathname.rb +7 -7
- data/spec/filters/bugs/proc.rb +63 -63
- data/spec/filters/bugs/random.rb +7 -6
- data/spec/filters/bugs/range.rb +12 -9
- data/spec/filters/bugs/rational.rb +8 -7
- data/spec/filters/bugs/regexp.rb +49 -48
- data/spec/filters/bugs/ruby-32.rb +56 -0
- data/spec/filters/bugs/set.rb +30 -30
- data/spec/filters/bugs/singleton.rb +4 -4
- data/spec/filters/bugs/string.rb +187 -99
- data/spec/filters/bugs/stringio.rb +7 -0
- data/spec/filters/bugs/stringscanner.rb +68 -68
- data/spec/filters/bugs/struct.rb +11 -9
- data/spec/filters/bugs/symbol.rb +1 -1
- data/spec/filters/bugs/time.rb +78 -63
- data/spec/filters/bugs/trace_point.rb +4 -4
- data/spec/filters/bugs/unboundmethod.rb +32 -17
- data/spec/filters/bugs/warnings.rb +8 -12
- data/spec/filters/unsupported/array.rb +24 -107
- data/spec/filters/unsupported/basicobject.rb +12 -12
- data/spec/filters/unsupported/bignum.rb +27 -52
- data/spec/filters/unsupported/class.rb +1 -2
- data/spec/filters/unsupported/delegator.rb +3 -3
- data/spec/filters/unsupported/enumerable.rb +2 -9
- data/spec/filters/unsupported/enumerator.rb +2 -11
- data/spec/filters/unsupported/file.rb +1 -1
- data/spec/filters/unsupported/float.rb +28 -47
- data/spec/filters/unsupported/hash.rb +8 -14
- data/spec/filters/unsupported/integer.rb +75 -91
- data/spec/filters/unsupported/kernel.rb +17 -35
- data/spec/filters/unsupported/language.rb +11 -19
- data/spec/filters/unsupported/marshal.rb +22 -41
- data/spec/filters/unsupported/matchdata.rb +28 -52
- data/spec/filters/unsupported/math.rb +1 -1
- data/spec/filters/unsupported/privacy.rb +229 -285
- data/spec/filters/unsupported/range.rb +1 -5
- data/spec/filters/unsupported/regexp.rb +40 -66
- data/spec/filters/unsupported/set.rb +2 -2
- data/spec/filters/unsupported/singleton.rb +4 -4
- data/spec/filters/unsupported/string.rb +305 -508
- data/spec/filters/unsupported/struct.rb +3 -4
- data/spec/filters/unsupported/symbol.rb +15 -18
- data/spec/filters/unsupported/thread.rb +1 -7
- data/spec/filters/unsupported/time.rb +159 -202
- data/spec/filters/unsupported/usage_of_files.rb +170 -259
- data/spec/lib/builder_spec.rb +4 -4
- data/spec/lib/rewriters/forward_args_spec.rb +32 -12
- data/spec/mspec-opal/runner.rb +2 -0
- data/spec/ruby_specs +4 -0
- data/stdlib/deno/base.rb +28 -0
- data/stdlib/deno/file.rb +340 -0
- data/stdlib/{headless_chrome.rb → headless_browser/base.rb} +1 -1
- data/stdlib/headless_browser/file.rb +15 -0
- data/stdlib/headless_browser.rb +4 -0
- data/stdlib/native.rb +1 -1
- data/stdlib/nodejs/file.rb +5 -0
- data/stdlib/opal/platform.rb +8 -6
- data/stdlib/opal-platform.rb +14 -8
- data/stdlib/set.rb +1 -258
- data/tasks/benchmarking.rake +62 -19
- data/tasks/performance.rake +1 -1
- data/tasks/testing.rake +5 -3
- data/test/nodejs/test_file.rb +29 -10
- data/test/opal/http_server.rb +28 -11
- data/test/opal/unsupported_and_bugs.rb +2 -1
- metadata +89 -50
- data/lib/opal/cli_runners/node_modules/ultron/LICENSE +0 -22
- data/lib/opal/cli_runners/node_modules/ultron/index.js +0 -138
- data/lib/opal/cli_runners/node_modules/ultron/package.json +0 -112
- data/lib/opal/cli_runners/node_modules/ws/SECURITY.md +0 -33
- data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.fallback.js +0 -56
- data/lib/opal/cli_runners/node_modules/ws/lib/BufferUtil.js +0 -15
- data/lib/opal/cli_runners/node_modules/ws/lib/ErrorCodes.js +0 -28
- data/lib/opal/cli_runners/node_modules/ws/lib/EventTarget.js +0 -158
- data/lib/opal/cli_runners/node_modules/ws/lib/Extensions.js +0 -69
- data/lib/opal/cli_runners/node_modules/ws/lib/PerMessageDeflate.js +0 -339
- data/lib/opal/cli_runners/node_modules/ws/lib/Receiver.js +0 -520
- data/lib/opal/cli_runners/node_modules/ws/lib/Sender.js +0 -438
- data/lib/opal/cli_runners/node_modules/ws/lib/Validation.fallback.js +0 -9
- data/lib/opal/cli_runners/node_modules/ws/lib/Validation.js +0 -17
- data/lib/opal/cli_runners/node_modules/ws/lib/WebSocket.js +0 -705
- data/lib/opal/cli_runners/node_modules/ws/lib/WebSocketServer.js +0 -336
- data/spec/filters/bugs/boolean.rb +0 -3
- data/spec/filters/bugs/matrix.rb +0 -3
- data/spec/filters/unsupported/fixnum.rb +0 -15
- data/spec/filters/unsupported/freeze.rb +0 -102
- data/spec/filters/unsupported/pathname.rb +0 -4
- data/spec/filters/unsupported/proc.rb +0 -4
- data/spec/filters/unsupported/random.rb +0 -5
- data/spec/filters/unsupported/taint.rb +0 -162
@@ -1,520 +0,0 @@
|
|
1
|
-
/*!
|
2
|
-
* ws: a node.js websocket client
|
3
|
-
* Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
4
|
-
* MIT Licensed
|
5
|
-
*/
|
6
|
-
|
7
|
-
'use strict';
|
8
|
-
|
9
|
-
const PerMessageDeflate = require('./PerMessageDeflate');
|
10
|
-
const isValidUTF8 = require('./Validation');
|
11
|
-
const bufferUtil = require('./BufferUtil');
|
12
|
-
const ErrorCodes = require('./ErrorCodes');
|
13
|
-
|
14
|
-
const EMPTY_BUFFER = Buffer.alloc(0);
|
15
|
-
|
16
|
-
const GET_INFO = 0;
|
17
|
-
const GET_PAYLOAD_LENGTH_16 = 1;
|
18
|
-
const GET_PAYLOAD_LENGTH_64 = 2;
|
19
|
-
const HAVE_LENGTH = 3;
|
20
|
-
const GET_MASK = 4;
|
21
|
-
const GET_DATA = 5;
|
22
|
-
const HANDLE_DATA = 6;
|
23
|
-
const INFLATING = 7;
|
24
|
-
|
25
|
-
/**
|
26
|
-
* HyBi Receiver implementation.
|
27
|
-
*/
|
28
|
-
class Receiver {
|
29
|
-
/**
|
30
|
-
* Creates a Receiver instance.
|
31
|
-
*
|
32
|
-
* @param {Object} extensions An object containing the negotiated extensions
|
33
|
-
* @param {Number} maxPayload The maximum allowed message length
|
34
|
-
*/
|
35
|
-
constructor (extensions, maxPayload) {
|
36
|
-
this.extensions = extensions || {};
|
37
|
-
this.maxPayload = maxPayload | 0;
|
38
|
-
|
39
|
-
this.bufferedBytes = 0;
|
40
|
-
this.buffers = [];
|
41
|
-
|
42
|
-
this.compressed = false;
|
43
|
-
this.payloadLength = 0;
|
44
|
-
this.fragmented = 0;
|
45
|
-
this.masked = false;
|
46
|
-
this.fin = false;
|
47
|
-
this.mask = null;
|
48
|
-
this.opcode = 0;
|
49
|
-
|
50
|
-
this.totalPayloadLength = 0;
|
51
|
-
this.messageLength = 0;
|
52
|
-
this.fragments = [];
|
53
|
-
|
54
|
-
this.cleanupCallback = null;
|
55
|
-
this.hadError = false;
|
56
|
-
this.dead = false;
|
57
|
-
|
58
|
-
this.onmessage = null;
|
59
|
-
this.onclose = null;
|
60
|
-
this.onerror = null;
|
61
|
-
this.onping = null;
|
62
|
-
this.onpong = null;
|
63
|
-
|
64
|
-
this.state = GET_INFO;
|
65
|
-
}
|
66
|
-
|
67
|
-
/**
|
68
|
-
* Consumes bytes from the available buffered data.
|
69
|
-
*
|
70
|
-
* @param {Number} bytes The number of bytes to consume
|
71
|
-
* @return {Buffer} Consumed bytes
|
72
|
-
* @private
|
73
|
-
*/
|
74
|
-
readBuffer (bytes) {
|
75
|
-
var offset = 0;
|
76
|
-
var dst;
|
77
|
-
var l;
|
78
|
-
|
79
|
-
this.bufferedBytes -= bytes;
|
80
|
-
|
81
|
-
if (bytes === this.buffers[0].length) return this.buffers.shift();
|
82
|
-
|
83
|
-
if (bytes < this.buffers[0].length) {
|
84
|
-
dst = this.buffers[0].slice(0, bytes);
|
85
|
-
this.buffers[0] = this.buffers[0].slice(bytes);
|
86
|
-
return dst;
|
87
|
-
}
|
88
|
-
|
89
|
-
dst = new Buffer(bytes);
|
90
|
-
|
91
|
-
while (bytes > 0) {
|
92
|
-
l = this.buffers[0].length;
|
93
|
-
|
94
|
-
if (bytes >= l) {
|
95
|
-
this.buffers[0].copy(dst, offset);
|
96
|
-
offset += l;
|
97
|
-
this.buffers.shift();
|
98
|
-
} else {
|
99
|
-
this.buffers[0].copy(dst, offset, 0, bytes);
|
100
|
-
this.buffers[0] = this.buffers[0].slice(bytes);
|
101
|
-
}
|
102
|
-
|
103
|
-
bytes -= l;
|
104
|
-
}
|
105
|
-
|
106
|
-
return dst;
|
107
|
-
}
|
108
|
-
|
109
|
-
/**
|
110
|
-
* Checks if the number of buffered bytes is bigger or equal than `n` and
|
111
|
-
* calls `cleanup` if necessary.
|
112
|
-
*
|
113
|
-
* @param {Number} n The number of bytes to check against
|
114
|
-
* @return {Boolean} `true` if `bufferedBytes >= n`, else `false`
|
115
|
-
* @private
|
116
|
-
*/
|
117
|
-
hasBufferedBytes (n) {
|
118
|
-
if (this.bufferedBytes >= n) return true;
|
119
|
-
|
120
|
-
if (this.dead) this.cleanup(this.cleanupCallback);
|
121
|
-
return false;
|
122
|
-
}
|
123
|
-
|
124
|
-
/**
|
125
|
-
* Adds new data to the parser.
|
126
|
-
*
|
127
|
-
* @public
|
128
|
-
*/
|
129
|
-
add (data) {
|
130
|
-
if (this.dead) return;
|
131
|
-
|
132
|
-
this.bufferedBytes += data.length;
|
133
|
-
this.buffers.push(data);
|
134
|
-
this.startLoop();
|
135
|
-
}
|
136
|
-
|
137
|
-
/**
|
138
|
-
* Starts the parsing loop.
|
139
|
-
*
|
140
|
-
* @private
|
141
|
-
*/
|
142
|
-
startLoop () {
|
143
|
-
while (true) {
|
144
|
-
if (this.state === GET_INFO) {
|
145
|
-
if (!this.getInfo()) break;
|
146
|
-
} else if (this.state === GET_PAYLOAD_LENGTH_16) {
|
147
|
-
if (!this.getPayloadLength16()) break;
|
148
|
-
} else if (this.state === GET_PAYLOAD_LENGTH_64) {
|
149
|
-
if (!this.getPayloadLength64()) break;
|
150
|
-
} else if (this.state === HAVE_LENGTH) {
|
151
|
-
if (!this.haveLength()) break;
|
152
|
-
} else if (this.state === GET_MASK) {
|
153
|
-
if (!this.getMask()) break;
|
154
|
-
} else if (this.state === GET_DATA) {
|
155
|
-
if (!this.getData()) break;
|
156
|
-
} else { // `HANDLE_DATA` or `INFLATING`
|
157
|
-
break;
|
158
|
-
}
|
159
|
-
}
|
160
|
-
}
|
161
|
-
|
162
|
-
/**
|
163
|
-
* Reads the first two bytes of a frame.
|
164
|
-
*
|
165
|
-
* @return {Boolean} `true` if the operation is successful, else `false`
|
166
|
-
* @private
|
167
|
-
*/
|
168
|
-
getInfo () {
|
169
|
-
if (!this.hasBufferedBytes(2)) return false;
|
170
|
-
|
171
|
-
const buf = this.readBuffer(2);
|
172
|
-
|
173
|
-
if ((buf[0] & 0x30) !== 0x00) {
|
174
|
-
this.error(new Error('RSV2 and RSV3 must be clear'), 1002);
|
175
|
-
return false;
|
176
|
-
}
|
177
|
-
|
178
|
-
const compressed = (buf[0] & 0x40) === 0x40;
|
179
|
-
|
180
|
-
if (compressed && !this.extensions[PerMessageDeflate.extensionName]) {
|
181
|
-
this.error(new Error('RSV1 must be clear'), 1002);
|
182
|
-
return false;
|
183
|
-
}
|
184
|
-
|
185
|
-
this.fin = (buf[0] & 0x80) === 0x80;
|
186
|
-
this.opcode = buf[0] & 0x0f;
|
187
|
-
this.payloadLength = buf[1] & 0x7f;
|
188
|
-
|
189
|
-
if (this.opcode === 0x00) {
|
190
|
-
if (compressed) {
|
191
|
-
this.error(new Error('RSV1 must be clear'), 1002);
|
192
|
-
return false;
|
193
|
-
}
|
194
|
-
|
195
|
-
if (!this.fragmented) {
|
196
|
-
this.error(new Error(`invalid opcode: ${this.opcode}`), 1002);
|
197
|
-
return false;
|
198
|
-
} else {
|
199
|
-
this.opcode = this.fragmented;
|
200
|
-
}
|
201
|
-
} else if (this.opcode === 0x01 || this.opcode === 0x02) {
|
202
|
-
if (this.fragmented) {
|
203
|
-
this.error(new Error(`invalid opcode: ${this.opcode}`), 1002);
|
204
|
-
return false;
|
205
|
-
}
|
206
|
-
|
207
|
-
this.compressed = compressed;
|
208
|
-
} else if (this.opcode > 0x07 && this.opcode < 0x0b) {
|
209
|
-
if (!this.fin) {
|
210
|
-
this.error(new Error('FIN must be set'), 1002);
|
211
|
-
return false;
|
212
|
-
}
|
213
|
-
|
214
|
-
if (compressed) {
|
215
|
-
this.error(new Error('RSV1 must be clear'), 1002);
|
216
|
-
return false;
|
217
|
-
}
|
218
|
-
|
219
|
-
if (this.payloadLength > 0x7d) {
|
220
|
-
this.error(new Error('invalid payload length'), 1002);
|
221
|
-
return false;
|
222
|
-
}
|
223
|
-
} else {
|
224
|
-
this.error(new Error(`invalid opcode: ${this.opcode}`), 1002);
|
225
|
-
return false;
|
226
|
-
}
|
227
|
-
|
228
|
-
if (!this.fin && !this.fragmented) this.fragmented = this.opcode;
|
229
|
-
|
230
|
-
this.masked = (buf[1] & 0x80) === 0x80;
|
231
|
-
|
232
|
-
if (this.payloadLength === 126) this.state = GET_PAYLOAD_LENGTH_16;
|
233
|
-
else if (this.payloadLength === 127) this.state = GET_PAYLOAD_LENGTH_64;
|
234
|
-
else this.state = HAVE_LENGTH;
|
235
|
-
|
236
|
-
return true;
|
237
|
-
}
|
238
|
-
|
239
|
-
/**
|
240
|
-
* Gets extended payload length (7+16).
|
241
|
-
*
|
242
|
-
* @return {Boolean} `true` if payload length has been read, else `false`
|
243
|
-
* @private
|
244
|
-
*/
|
245
|
-
getPayloadLength16 () {
|
246
|
-
if (!this.hasBufferedBytes(2)) return false;
|
247
|
-
|
248
|
-
this.payloadLength = this.readBuffer(2).readUInt16BE(0, true);
|
249
|
-
this.state = HAVE_LENGTH;
|
250
|
-
return true;
|
251
|
-
}
|
252
|
-
|
253
|
-
/**
|
254
|
-
* Gets extended payload length (7+64).
|
255
|
-
*
|
256
|
-
* @return {Boolean} `true` if payload length has been read, else `false`
|
257
|
-
* @private
|
258
|
-
*/
|
259
|
-
getPayloadLength64 () {
|
260
|
-
if (!this.hasBufferedBytes(8)) return false;
|
261
|
-
|
262
|
-
const buf = this.readBuffer(8);
|
263
|
-
const num = buf.readUInt32BE(0, true);
|
264
|
-
|
265
|
-
//
|
266
|
-
// The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
|
267
|
-
// if payload length is greater than this number.
|
268
|
-
//
|
269
|
-
if (num > Math.pow(2, 53 - 32) - 1) {
|
270
|
-
this.error(new Error('max payload size exceeded'), 1009);
|
271
|
-
return false;
|
272
|
-
}
|
273
|
-
|
274
|
-
this.payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4, true);
|
275
|
-
this.state = HAVE_LENGTH;
|
276
|
-
return true;
|
277
|
-
}
|
278
|
-
|
279
|
-
/**
|
280
|
-
* Payload length has been read.
|
281
|
-
*
|
282
|
-
* @return {Boolean} `false` if payload length exceeds `maxPayload`, else `true`
|
283
|
-
* @private
|
284
|
-
*/
|
285
|
-
haveLength () {
|
286
|
-
if (this.opcode < 0x08 && this.maxPayloadExceeded(this.payloadLength)) {
|
287
|
-
return false;
|
288
|
-
}
|
289
|
-
|
290
|
-
if (this.masked) this.state = GET_MASK;
|
291
|
-
else this.state = GET_DATA;
|
292
|
-
return true;
|
293
|
-
}
|
294
|
-
|
295
|
-
/**
|
296
|
-
* Reads mask bytes.
|
297
|
-
*
|
298
|
-
* @return {Boolean} `true` if the mask has been read, else `false`
|
299
|
-
* @private
|
300
|
-
*/
|
301
|
-
getMask () {
|
302
|
-
if (!this.hasBufferedBytes(4)) return false;
|
303
|
-
|
304
|
-
this.mask = this.readBuffer(4);
|
305
|
-
this.state = GET_DATA;
|
306
|
-
return true;
|
307
|
-
}
|
308
|
-
|
309
|
-
/**
|
310
|
-
* Reads data bytes.
|
311
|
-
*
|
312
|
-
* @return {Boolean} `true` if the data bytes have been read, else `false`
|
313
|
-
* @private
|
314
|
-
*/
|
315
|
-
getData () {
|
316
|
-
var data = EMPTY_BUFFER;
|
317
|
-
|
318
|
-
if (this.payloadLength) {
|
319
|
-
if (!this.hasBufferedBytes(this.payloadLength)) return false;
|
320
|
-
|
321
|
-
data = this.readBuffer(this.payloadLength);
|
322
|
-
if (this.masked) bufferUtil.unmask(data, this.mask);
|
323
|
-
}
|
324
|
-
|
325
|
-
this.state = HANDLE_DATA;
|
326
|
-
|
327
|
-
if (this.opcode > 0x07) {
|
328
|
-
this.controlMessage(data);
|
329
|
-
} else if (this.compressed) {
|
330
|
-
this.state = INFLATING;
|
331
|
-
this.decompress(data);
|
332
|
-
} else if (this.pushFragment(data)) {
|
333
|
-
this.dataMessage();
|
334
|
-
}
|
335
|
-
|
336
|
-
return true;
|
337
|
-
}
|
338
|
-
|
339
|
-
/**
|
340
|
-
* Decompresses data.
|
341
|
-
*
|
342
|
-
* @param {Buffer} data Compressed data
|
343
|
-
* @private
|
344
|
-
*/
|
345
|
-
decompress (data) {
|
346
|
-
const extension = this.extensions[PerMessageDeflate.extensionName];
|
347
|
-
|
348
|
-
extension.decompress(data, this.fin, (err, buf) => {
|
349
|
-
if (err) {
|
350
|
-
this.error(err, err.closeCode === 1009 ? 1009 : 1007);
|
351
|
-
return;
|
352
|
-
}
|
353
|
-
|
354
|
-
if (this.pushFragment(buf)) this.dataMessage();
|
355
|
-
if (this.state === GET_INFO) this.startLoop();
|
356
|
-
});
|
357
|
-
}
|
358
|
-
|
359
|
-
/**
|
360
|
-
* Handles a data message.
|
361
|
-
*
|
362
|
-
* @private
|
363
|
-
*/
|
364
|
-
dataMessage () {
|
365
|
-
if (this.fin) {
|
366
|
-
const buf = this.fragments.length > 1
|
367
|
-
? Buffer.concat(this.fragments, this.messageLength)
|
368
|
-
: this.fragments.length === 1
|
369
|
-
? this.fragments[0]
|
370
|
-
: EMPTY_BUFFER;
|
371
|
-
|
372
|
-
this.totalPayloadLength = 0;
|
373
|
-
this.fragments.length = 0;
|
374
|
-
this.messageLength = 0;
|
375
|
-
this.fragmented = 0;
|
376
|
-
|
377
|
-
if (this.opcode === 2) {
|
378
|
-
this.onmessage(buf, { masked: this.masked, binary: true });
|
379
|
-
} else {
|
380
|
-
if (!isValidUTF8(buf)) {
|
381
|
-
this.error(new Error('invalid utf8 sequence'), 1007);
|
382
|
-
return;
|
383
|
-
}
|
384
|
-
|
385
|
-
this.onmessage(buf.toString(), { masked: this.masked });
|
386
|
-
}
|
387
|
-
}
|
388
|
-
|
389
|
-
this.state = GET_INFO;
|
390
|
-
}
|
391
|
-
|
392
|
-
/**
|
393
|
-
* Handles a control message.
|
394
|
-
*
|
395
|
-
* @param {Buffer} data Data to handle
|
396
|
-
* @private
|
397
|
-
*/
|
398
|
-
controlMessage (data) {
|
399
|
-
if (this.opcode === 0x08) {
|
400
|
-
if (data.length === 0) {
|
401
|
-
this.onclose(1000, '', { masked: this.masked });
|
402
|
-
this.cleanup(this.cleanupCallback);
|
403
|
-
} else if (data.length === 1) {
|
404
|
-
this.error(new Error('invalid payload length'), 1002);
|
405
|
-
} else {
|
406
|
-
const code = data.readUInt16BE(0, true);
|
407
|
-
|
408
|
-
if (!ErrorCodes.isValidErrorCode(code)) {
|
409
|
-
this.error(new Error(`invalid status code: ${code}`), 1002);
|
410
|
-
return;
|
411
|
-
}
|
412
|
-
|
413
|
-
const buf = data.slice(2);
|
414
|
-
|
415
|
-
if (!isValidUTF8(buf)) {
|
416
|
-
this.error(new Error('invalid utf8 sequence'), 1007);
|
417
|
-
return;
|
418
|
-
}
|
419
|
-
|
420
|
-
this.onclose(code, buf.toString(), { masked: this.masked });
|
421
|
-
this.cleanup(this.cleanupCallback);
|
422
|
-
}
|
423
|
-
|
424
|
-
return;
|
425
|
-
}
|
426
|
-
|
427
|
-
const flags = { masked: this.masked, binary: true };
|
428
|
-
|
429
|
-
if (this.opcode === 0x09) this.onping(data, flags);
|
430
|
-
else this.onpong(data, flags);
|
431
|
-
|
432
|
-
this.state = GET_INFO;
|
433
|
-
}
|
434
|
-
|
435
|
-
/**
|
436
|
-
* Handles an error.
|
437
|
-
*
|
438
|
-
* @param {Error} err The error
|
439
|
-
* @param {Number} code Close code
|
440
|
-
* @private
|
441
|
-
*/
|
442
|
-
error (err, code) {
|
443
|
-
this.onerror(err, code);
|
444
|
-
this.hadError = true;
|
445
|
-
this.cleanup(this.cleanupCallback);
|
446
|
-
}
|
447
|
-
|
448
|
-
/**
|
449
|
-
* Checks payload size, disconnects socket when it exceeds `maxPayload`.
|
450
|
-
*
|
451
|
-
* @param {Number} length Payload length
|
452
|
-
* @private
|
453
|
-
*/
|
454
|
-
maxPayloadExceeded (length) {
|
455
|
-
if (length === 0 || this.maxPayload < 1) return false;
|
456
|
-
|
457
|
-
const fullLength = this.totalPayloadLength + length;
|
458
|
-
|
459
|
-
if (fullLength <= this.maxPayload) {
|
460
|
-
this.totalPayloadLength = fullLength;
|
461
|
-
return false;
|
462
|
-
}
|
463
|
-
|
464
|
-
this.error(new Error('max payload size exceeded'), 1009);
|
465
|
-
return true;
|
466
|
-
}
|
467
|
-
|
468
|
-
/**
|
469
|
-
* Appends a fragment in the fragments array after checking that the sum of
|
470
|
-
* fragment lengths does not exceed `maxPayload`.
|
471
|
-
*
|
472
|
-
* @param {Buffer} fragment The fragment to add
|
473
|
-
* @return {Boolean} `true` if `maxPayload` is not exceeded, else `false`
|
474
|
-
* @private
|
475
|
-
*/
|
476
|
-
pushFragment (fragment) {
|
477
|
-
if (fragment.length === 0) return true;
|
478
|
-
|
479
|
-
const totalLength = this.messageLength + fragment.length;
|
480
|
-
|
481
|
-
if (this.maxPayload < 1 || totalLength <= this.maxPayload) {
|
482
|
-
this.messageLength = totalLength;
|
483
|
-
this.fragments.push(fragment);
|
484
|
-
return true;
|
485
|
-
}
|
486
|
-
|
487
|
-
this.error(new Error('max payload size exceeded'), 1009);
|
488
|
-
return false;
|
489
|
-
}
|
490
|
-
|
491
|
-
/**
|
492
|
-
* Releases resources used by the receiver.
|
493
|
-
*
|
494
|
-
* @param {Function} cb Callback
|
495
|
-
* @public
|
496
|
-
*/
|
497
|
-
cleanup (cb) {
|
498
|
-
this.dead = true;
|
499
|
-
|
500
|
-
if (!this.hadError && this.state === INFLATING) {
|
501
|
-
this.cleanupCallback = cb;
|
502
|
-
} else {
|
503
|
-
this.extensions = null;
|
504
|
-
this.fragments = null;
|
505
|
-
this.buffers = null;
|
506
|
-
this.mask = null;
|
507
|
-
|
508
|
-
this.cleanupCallback = null;
|
509
|
-
this.onmessage = null;
|
510
|
-
this.onclose = null;
|
511
|
-
this.onerror = null;
|
512
|
-
this.onping = null;
|
513
|
-
this.onpong = null;
|
514
|
-
|
515
|
-
if (cb) cb();
|
516
|
-
}
|
517
|
-
}
|
518
|
-
}
|
519
|
-
|
520
|
-
module.exports = Receiver;
|