dragonfly_chrome_headless 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +4 -0
  5. data/README.md +53 -0
  6. data/Rakefile +10 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/dragonfly_chrome_headless.gemspec +27 -0
  10. data/lib/dragonfly_chrome_headless.rb +9 -0
  11. data/lib/dragonfly_chrome_headless/plugin.rb +17 -0
  12. data/lib/dragonfly_chrome_headless/processors/rasterize.rb +33 -0
  13. data/lib/dragonfly_chrome_headless/version.rb +3 -0
  14. data/node_modules/.bin/chrome-remote-interface +1 -0
  15. data/node_modules/.bin/mkdirp +1 -0
  16. data/node_modules/.bin/rimraf +1 -0
  17. data/node_modules/@types/core-js/LICENSE +21 -0
  18. data/node_modules/@types/core-js/README.md +16 -0
  19. data/node_modules/@types/core-js/index.d.ts +2452 -0
  20. data/node_modules/@types/core-js/package.json +85 -0
  21. data/node_modules/@types/mkdirp/README.md +18 -0
  22. data/node_modules/@types/mkdirp/index.d.ts +14 -0
  23. data/node_modules/@types/mkdirp/package.json +77 -0
  24. data/node_modules/@types/mkdirp/types-metadata.json +25 -0
  25. data/node_modules/@types/node/README.md +16 -0
  26. data/node_modules/@types/node/index.d.ts +4132 -0
  27. data/node_modules/@types/node/package.json +84 -0
  28. data/node_modules/balanced-match/.npmignore +5 -0
  29. data/node_modules/balanced-match/LICENSE.md +21 -0
  30. data/node_modules/balanced-match/README.md +91 -0
  31. data/node_modules/balanced-match/index.js +59 -0
  32. data/node_modules/balanced-match/package.json +112 -0
  33. data/node_modules/brace-expansion/README.md +123 -0
  34. data/node_modules/brace-expansion/index.js +201 -0
  35. data/node_modules/brace-expansion/package.json +114 -0
  36. data/node_modules/chrome-launcher/.clang-format +6 -0
  37. data/node_modules/chrome-launcher/.npmignore +11 -0
  38. data/node_modules/chrome-launcher/README.md +123 -0
  39. data/node_modules/chrome-launcher/ask.js +32 -0
  40. data/node_modules/chrome-launcher/ask.ts +35 -0
  41. data/node_modules/chrome-launcher/chrome-finder.js +157 -0
  42. data/node_modules/chrome-launcher/chrome-finder.ts +186 -0
  43. data/node_modules/chrome-launcher/chrome-launcher.js +245 -0
  44. data/node_modules/chrome-launcher/chrome-launcher.ts +312 -0
  45. data/node_modules/chrome-launcher/compiled-check.js +14 -0
  46. data/node_modules/chrome-launcher/flags.js +27 -0
  47. data/node_modules/chrome-launcher/flags.ts +26 -0
  48. data/node_modules/chrome-launcher/index.js +7 -0
  49. data/node_modules/chrome-launcher/index.ts +1 -0
  50. data/node_modules/chrome-launcher/manual-chrome-launcher.js +30 -0
  51. data/node_modules/chrome-launcher/package.json +116 -0
  52. data/node_modules/chrome-launcher/random-port.js +24 -0
  53. data/node_modules/chrome-launcher/random-port.ts +23 -0
  54. data/node_modules/chrome-launcher/tsconfig.json +19 -0
  55. data/node_modules/chrome-launcher/utils.js +52 -0
  56. data/node_modules/chrome-launcher/utils.ts +44 -0
  57. data/node_modules/chrome-launcher/yarn.lock +1486 -0
  58. data/node_modules/chrome-remote-interface/LICENSE +18 -0
  59. data/node_modules/chrome-remote-interface/README.md +849 -0
  60. data/node_modules/chrome-remote-interface/bin/client.js +337 -0
  61. data/node_modules/chrome-remote-interface/chrome-remote-interface.js +11 -0
  62. data/node_modules/chrome-remote-interface/index.js +39 -0
  63. data/node_modules/chrome-remote-interface/lib/api.js +84 -0
  64. data/node_modules/chrome-remote-interface/lib/chrome.js +307 -0
  65. data/node_modules/chrome-remote-interface/lib/defaults.js +4 -0
  66. data/node_modules/chrome-remote-interface/lib/devtools.js +245 -0
  67. data/node_modules/chrome-remote-interface/lib/external-request.js +28 -0
  68. data/node_modules/chrome-remote-interface/lib/protocol.json +13780 -0
  69. data/node_modules/chrome-remote-interface/lib/websocket-wrapper.js +32 -0
  70. data/node_modules/chrome-remote-interface/package.json +128 -0
  71. data/node_modules/chrome-remote-interface/webpack.config.js +55 -0
  72. data/node_modules/commander/Readme.md +195 -0
  73. data/node_modules/commander/index.js +851 -0
  74. data/node_modules/commander/package.json +92 -0
  75. data/node_modules/concat-map/.travis.yml +4 -0
  76. data/node_modules/concat-map/LICENSE +18 -0
  77. data/node_modules/concat-map/README.markdown +62 -0
  78. data/node_modules/concat-map/example/map.js +6 -0
  79. data/node_modules/concat-map/index.js +13 -0
  80. data/node_modules/concat-map/package.json +117 -0
  81. data/node_modules/concat-map/test/map.js +39 -0
  82. data/node_modules/debug/.coveralls.yml +1 -0
  83. data/node_modules/debug/.eslintrc +11 -0
  84. data/node_modules/debug/.npmignore +9 -0
  85. data/node_modules/debug/.travis.yml +14 -0
  86. data/node_modules/debug/CHANGELOG.md +357 -0
  87. data/node_modules/debug/LICENSE +19 -0
  88. data/node_modules/debug/Makefile +50 -0
  89. data/node_modules/debug/Readme.md +312 -0
  90. data/node_modules/debug/component.json +19 -0
  91. data/node_modules/debug/karma.conf.js +70 -0
  92. data/node_modules/debug/node.js +1 -0
  93. data/node_modules/debug/package.json +124 -0
  94. data/node_modules/debug/src/browser.js +185 -0
  95. data/node_modules/debug/src/debug.js +202 -0
  96. data/node_modules/debug/src/index.js +10 -0
  97. data/node_modules/debug/src/node.js +246 -0
  98. data/node_modules/fs.realpath/LICENSE +43 -0
  99. data/node_modules/fs.realpath/README.md +33 -0
  100. data/node_modules/fs.realpath/index.js +66 -0
  101. data/node_modules/fs.realpath/old.js +303 -0
  102. data/node_modules/fs.realpath/package.json +94 -0
  103. data/node_modules/glob/LICENSE +15 -0
  104. data/node_modules/glob/README.md +368 -0
  105. data/node_modules/glob/changelog.md +67 -0
  106. data/node_modules/glob/common.js +240 -0
  107. data/node_modules/glob/glob.js +790 -0
  108. data/node_modules/glob/package.json +112 -0
  109. data/node_modules/glob/sync.js +486 -0
  110. data/node_modules/html-pdf-chrome/.npmignore +9 -0
  111. data/node_modules/html-pdf-chrome/LICENSE +21 -0
  112. data/node_modules/html-pdf-chrome/README.md +165 -0
  113. data/node_modules/html-pdf-chrome/lib/src/ChromePrintOptions.d.ts +87 -0
  114. data/node_modules/html-pdf-chrome/lib/src/ChromePrintOptions.js +4 -0
  115. data/node_modules/html-pdf-chrome/lib/src/ChromePrintOptions.js.map +1 -0
  116. data/node_modules/html-pdf-chrome/lib/src/CompletionTrigger.d.ts +120 -0
  117. data/node_modules/html-pdf-chrome/lib/src/CompletionTrigger.js +206 -0
  118. data/node_modules/html-pdf-chrome/lib/src/CompletionTrigger.js.map +1 -0
  119. data/node_modules/html-pdf-chrome/lib/src/CreateResult.d.ts +70 -0
  120. data/node_modules/html-pdf-chrome/lib/src/CreateResult.js +98 -0
  121. data/node_modules/html-pdf-chrome/lib/src/CreateResult.js.map +1 -0
  122. data/node_modules/html-pdf-chrome/lib/src/index.d.ts +72 -0
  123. data/node_modules/html-pdf-chrome/lib/src/index.js +123 -0
  124. data/node_modules/html-pdf-chrome/lib/src/index.js.map +1 -0
  125. data/node_modules/html-pdf-chrome/package.json +133 -0
  126. data/node_modules/html-pdf-chrome/src/ChromePrintOptions.ts +99 -0
  127. data/node_modules/html-pdf-chrome/src/CompletionTrigger.ts +201 -0
  128. data/node_modules/html-pdf-chrome/src/CreateResult.ts +100 -0
  129. data/node_modules/html-pdf-chrome/src/index.ts +179 -0
  130. data/node_modules/inflight/LICENSE +15 -0
  131. data/node_modules/inflight/README.md +37 -0
  132. data/node_modules/inflight/inflight.js +54 -0
  133. data/node_modules/inflight/package.json +105 -0
  134. data/node_modules/inherits/LICENSE +16 -0
  135. data/node_modules/inherits/README.md +42 -0
  136. data/node_modules/inherits/inherits.js +7 -0
  137. data/node_modules/inherits/inherits_browser.js +23 -0
  138. data/node_modules/inherits/package.json +97 -0
  139. data/node_modules/lighthouse-logger/README.md +4 -0
  140. data/node_modules/lighthouse-logger/index.js +212 -0
  141. data/node_modules/lighthouse-logger/package.json +69 -0
  142. data/node_modules/lighthouse-logger/yarn.lock +13 -0
  143. data/node_modules/minimatch/LICENSE +15 -0
  144. data/node_modules/minimatch/README.md +209 -0
  145. data/node_modules/minimatch/minimatch.js +923 -0
  146. data/node_modules/minimatch/package.json +99 -0
  147. data/node_modules/minimist/.travis.yml +4 -0
  148. data/node_modules/minimist/LICENSE +18 -0
  149. data/node_modules/minimist/example/parse.js +2 -0
  150. data/node_modules/minimist/index.js +187 -0
  151. data/node_modules/minimist/package.json +101 -0
  152. data/node_modules/minimist/readme.markdown +73 -0
  153. data/node_modules/minimist/test/dash.js +24 -0
  154. data/node_modules/minimist/test/default_bool.js +20 -0
  155. data/node_modules/minimist/test/dotted.js +16 -0
  156. data/node_modules/minimist/test/long.js +31 -0
  157. data/node_modules/minimist/test/parse.js +318 -0
  158. data/node_modules/minimist/test/parse_modified.js +9 -0
  159. data/node_modules/minimist/test/short.js +67 -0
  160. data/node_modules/minimist/test/whitespace.js +8 -0
  161. data/node_modules/mkdirp/.travis.yml +8 -0
  162. data/node_modules/mkdirp/LICENSE +21 -0
  163. data/node_modules/mkdirp/bin/cmd.js +33 -0
  164. data/node_modules/mkdirp/bin/usage.txt +12 -0
  165. data/node_modules/mkdirp/examples/pow.js +6 -0
  166. data/node_modules/mkdirp/index.js +98 -0
  167. data/node_modules/mkdirp/package.json +93 -0
  168. data/node_modules/mkdirp/readme.markdown +100 -0
  169. data/node_modules/mkdirp/test/chmod.js +41 -0
  170. data/node_modules/mkdirp/test/clobber.js +38 -0
  171. data/node_modules/mkdirp/test/mkdirp.js +28 -0
  172. data/node_modules/mkdirp/test/opts_fs.js +29 -0
  173. data/node_modules/mkdirp/test/opts_fs_sync.js +27 -0
  174. data/node_modules/mkdirp/test/perm.js +32 -0
  175. data/node_modules/mkdirp/test/perm_sync.js +36 -0
  176. data/node_modules/mkdirp/test/race.js +37 -0
  177. data/node_modules/mkdirp/test/rel.js +32 -0
  178. data/node_modules/mkdirp/test/return.js +25 -0
  179. data/node_modules/mkdirp/test/return_sync.js +24 -0
  180. data/node_modules/mkdirp/test/root.js +19 -0
  181. data/node_modules/mkdirp/test/sync.js +32 -0
  182. data/node_modules/mkdirp/test/umask.js +28 -0
  183. data/node_modules/mkdirp/test/umask_sync.js +32 -0
  184. data/node_modules/ms/README.md +51 -0
  185. data/node_modules/ms/index.js +152 -0
  186. data/node_modules/ms/license.md +21 -0
  187. data/node_modules/ms/package.json +109 -0
  188. data/node_modules/once/LICENSE +15 -0
  189. data/node_modules/once/README.md +79 -0
  190. data/node_modules/once/once.js +42 -0
  191. data/node_modules/once/package.json +101 -0
  192. data/node_modules/path-is-absolute/index.js +20 -0
  193. data/node_modules/path-is-absolute/license +21 -0
  194. data/node_modules/path-is-absolute/package.json +111 -0
  195. data/node_modules/path-is-absolute/readme.md +59 -0
  196. data/node_modules/rimraf/LICENSE +15 -0
  197. data/node_modules/rimraf/README.md +101 -0
  198. data/node_modules/rimraf/bin.js +50 -0
  199. data/node_modules/rimraf/package.json +99 -0
  200. data/node_modules/rimraf/rimraf.js +363 -0
  201. data/node_modules/ultron/LICENSE +22 -0
  202. data/node_modules/ultron/index.js +138 -0
  203. data/node_modules/ultron/package.json +112 -0
  204. data/node_modules/wrappy/LICENSE +15 -0
  205. data/node_modules/wrappy/README.md +36 -0
  206. data/node_modules/wrappy/package.json +97 -0
  207. data/node_modules/wrappy/wrappy.js +33 -0
  208. data/node_modules/ws/LICENSE +21 -0
  209. data/node_modules/ws/README.md +259 -0
  210. data/node_modules/ws/SECURITY.md +33 -0
  211. data/node_modules/ws/index.js +15 -0
  212. data/node_modules/ws/lib/BufferUtil.fallback.js +56 -0
  213. data/node_modules/ws/lib/BufferUtil.js +15 -0
  214. data/node_modules/ws/lib/ErrorCodes.js +28 -0
  215. data/node_modules/ws/lib/EventTarget.js +158 -0
  216. data/node_modules/ws/lib/Extensions.js +69 -0
  217. data/node_modules/ws/lib/PerMessageDeflate.js +339 -0
  218. data/node_modules/ws/lib/Receiver.js +520 -0
  219. data/node_modules/ws/lib/Sender.js +438 -0
  220. data/node_modules/ws/lib/Validation.fallback.js +9 -0
  221. data/node_modules/ws/lib/Validation.js +17 -0
  222. data/node_modules/ws/lib/WebSocket.js +705 -0
  223. data/node_modules/ws/lib/WebSocketServer.js +336 -0
  224. data/node_modules/ws/package.json +122 -0
  225. data/package.json +26 -0
  226. data/samples/sample.html +13 -0
  227. data/script/rasterize.js +18 -0
  228. metadata +325 -0
@@ -0,0 +1,520 @@
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;