ed3-precompiled_websocket-driver 0.8.0-arm64-darwin

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.
@@ -0,0 +1,426 @@
1
+ # frozen_string_literal: false
2
+
3
+ module WebSocket
4
+ class Driver
5
+
6
+ class Hybi < Driver
7
+ root = File.expand_path('../hybi', __FILE__)
8
+
9
+ autoload :Frame, root + '/frame'
10
+ autoload :Message, root + '/message'
11
+
12
+ def self.generate_accept(key)
13
+ Base64.strict_encode64(Digest::SHA1.digest(key + GUID))
14
+ end
15
+
16
+ VERSION = '13'
17
+ GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
18
+
19
+ BYTE = 0b11111111
20
+ FIN = MASK = 0b10000000
21
+ RSV1 = 0b01000000
22
+ RSV2 = 0b00100000
23
+ RSV3 = 0b00010000
24
+ OPCODE = 0b00001111
25
+ LENGTH = 0b01111111
26
+
27
+ OPCODES = {
28
+ :continuation => 0,
29
+ :text => 1,
30
+ :binary => 2,
31
+ :close => 8,
32
+ :ping => 9,
33
+ :pong => 10
34
+ }
35
+
36
+ OPCODE_CODES = OPCODES.values
37
+ MESSAGE_OPCODES = OPCODES.values_at(:continuation, :text, :binary)
38
+ OPENING_OPCODES = OPCODES.values_at(:text, :binary)
39
+
40
+ ERRORS = {
41
+ :normal_closure => 1000,
42
+ :going_away => 1001,
43
+ :protocol_error => 1002,
44
+ :unacceptable => 1003,
45
+ :encoding_error => 1007,
46
+ :policy_violation => 1008,
47
+ :too_large => 1009,
48
+ :extension_error => 1010,
49
+ :unexpected_condition => 1011
50
+ }
51
+
52
+ ERROR_CODES = ERRORS.values
53
+ DEFAULT_ERROR_CODE = 1000
54
+ MIN_RESERVED_ERROR = 3000
55
+ MAX_RESERVED_ERROR = 4999
56
+
57
+ PACK_FORMATS = { 2 => 'S>', 8 => 'Q>' }
58
+
59
+ def initialize(socket, options = {})
60
+ super
61
+
62
+ @extensions = ::WebSocket::Extensions.new
63
+ @stage = 0
64
+ @masking = options[:masking]
65
+ @protocols = options[:protocols] || []
66
+ @protocols = @protocols.strip.split(/ *, */) if String === @protocols
67
+ @require_masking = options[:require_masking]
68
+ @ping_callbacks = {}
69
+
70
+ @frame = @message = nil
71
+
72
+ return unless @socket.respond_to?(:env)
73
+
74
+ if protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
75
+ protos = protos.split(/ *, */) if String === protos
76
+ @protocol = protos.find { |p| @protocols.include?(p) }
77
+ else
78
+ @protocol = nil
79
+ end
80
+ end
81
+
82
+ def version
83
+ "hybi-#{ VERSION }"
84
+ end
85
+
86
+ def add_extension(extension)
87
+ @extensions.add(extension)
88
+ true
89
+ end
90
+
91
+ def parse(chunk)
92
+ @reader.put(chunk)
93
+ buffer = true
94
+ while buffer
95
+ case @stage
96
+ when 0 then
97
+ buffer = @reader.read(1)
98
+ parse_opcode(buffer.getbyte(0)) if buffer
99
+
100
+ when 1 then
101
+ buffer = @reader.read(1)
102
+ parse_length(buffer.getbyte(0)) if buffer
103
+
104
+ when 2 then
105
+ buffer = @reader.read(@frame.length_bytes)
106
+ parse_extended_length(buffer) if buffer
107
+
108
+ when 3 then
109
+ buffer = @reader.read(4)
110
+ if buffer
111
+ @stage = 4
112
+ @frame.masking_key = buffer
113
+ end
114
+
115
+ when 4 then
116
+ buffer = @reader.read(@frame.length)
117
+
118
+ if buffer
119
+ @stage = 0
120
+ emit_frame(buffer)
121
+ end
122
+
123
+ else
124
+ buffer = nil
125
+ end
126
+ end
127
+ end
128
+
129
+ def binary(message)
130
+ frame(message, :binary)
131
+ end
132
+
133
+ def ping(message = '', &callback)
134
+ @ping_callbacks[message] = callback if callback
135
+ frame(message, :ping)
136
+ end
137
+
138
+ def pong(message = '')
139
+ frame(message, :pong)
140
+ end
141
+
142
+ def close(reason = nil, code = nil)
143
+ reason ||= ''
144
+ code ||= ERRORS[:normal_closure]
145
+
146
+ if @ready_state <= 0
147
+ @ready_state = 3
148
+ emit(:close, CloseEvent.new(code, reason))
149
+ true
150
+ elsif @ready_state == 1
151
+ frame(reason, :close, code)
152
+ @ready_state = 2
153
+ true
154
+ else
155
+ false
156
+ end
157
+ end
158
+
159
+ def frame(buffer, type = nil, code = nil)
160
+ return queue([buffer, type, code]) if @ready_state <= 0
161
+ return false unless @ready_state == 1
162
+
163
+ message = Message.new
164
+ frame = Frame.new
165
+
166
+ is_binary = (Array === buffer or buffer.encoding == Encoding::BINARY)
167
+ payload = Driver.encode(buffer, is_binary ? nil : Encoding::UTF_8)
168
+ payload = [code, payload].pack('S>a*') if code
169
+ type ||= is_binary ? :binary : :text
170
+
171
+ message.rsv1 = message.rsv2 = message.rsv3 = false
172
+ message.opcode = OPCODES[type]
173
+ message.data = payload
174
+
175
+ if MESSAGE_OPCODES.include?(message.opcode)
176
+ message = @extensions.process_outgoing_message(message)
177
+ end
178
+
179
+ frame.final = true
180
+ frame.rsv1 = message.rsv1
181
+ frame.rsv2 = message.rsv2
182
+ frame.rsv3 = message.rsv3
183
+ frame.opcode = message.opcode
184
+ frame.masked = !!@masking
185
+ frame.masking_key = SecureRandom.random_bytes(4) if frame.masked
186
+ frame.length = message.data.bytesize
187
+ frame.payload = message.data
188
+
189
+ send_frame(frame)
190
+ true
191
+
192
+ rescue ::WebSocket::Extensions::ExtensionError => error
193
+ fail(:extension_error, error.message)
194
+ end
195
+
196
+ private
197
+
198
+ def send_frame(frame)
199
+ length = frame.length
200
+ values = []
201
+ format = 'C2'
202
+ masked = frame.masked ? MASK : 0
203
+
204
+ values[0] = (frame.final ? FIN : 0) |
205
+ (frame.rsv1 ? RSV1 : 0) |
206
+ (frame.rsv2 ? RSV2 : 0) |
207
+ (frame.rsv3 ? RSV3 : 0) |
208
+ frame.opcode
209
+
210
+ if length <= 125
211
+ values[1] = masked | length
212
+ elsif length <= 65535
213
+ values[1] = masked | 126
214
+ values[2] = length
215
+ format << 'S>'
216
+ else
217
+ values[1] = masked | 127
218
+ values[2] = length
219
+ format << 'Q>'
220
+ end
221
+
222
+ if frame.masked
223
+ values << frame.masking_key
224
+ values << Mask.mask(frame.payload, frame.masking_key)
225
+ format << 'a4a*'
226
+ else
227
+ values << frame.payload
228
+ format << 'a*'
229
+ end
230
+
231
+ @socket.write(values.pack(format))
232
+ end
233
+
234
+ def handshake_response
235
+ sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
236
+ version = @socket.env['HTTP_SEC_WEBSOCKET_VERSION']
237
+
238
+ unless version == VERSION
239
+ raise ProtocolError.new("Unsupported WebSocket version: #{ VERSION }")
240
+ end
241
+
242
+ unless sec_key
243
+ raise ProtocolError.new('Missing handshake request header: Sec-WebSocket-Key')
244
+ end
245
+
246
+ @headers['Upgrade'] = 'websocket'
247
+ @headers['Connection'] = 'Upgrade'
248
+ @headers['Sec-WebSocket-Accept'] = Hybi.generate_accept(sec_key)
249
+
250
+ @headers['Sec-WebSocket-Protocol'] = @protocol if @protocol
251
+
252
+ extensions = @extensions.generate_response(@socket.env['HTTP_SEC_WEBSOCKET_EXTENSIONS'])
253
+ @headers['Sec-WebSocket-Extensions'] = extensions if extensions
254
+
255
+ start = 'HTTP/1.1 101 Switching Protocols'
256
+ headers = [start, @headers.to_s, '']
257
+ headers.join("\r\n")
258
+ end
259
+
260
+ def shutdown(code, reason, error = false)
261
+ @frame = @message = nil
262
+ @stage = 5
263
+ @extensions.close
264
+
265
+ frame(reason, :close, code) if @ready_state < 2
266
+ @ready_state = 3
267
+
268
+ emit(:error, ProtocolError.new(reason)) if error
269
+ emit(:close, CloseEvent.new(code, reason))
270
+ end
271
+
272
+ def fail(type, message)
273
+ return if @ready_state > 1
274
+ shutdown(ERRORS[type], message, true)
275
+ end
276
+
277
+ def parse_opcode(octet)
278
+ rsvs = [RSV1, RSV2, RSV3].map { |rsv| (octet & rsv) == rsv }
279
+
280
+ @frame = Frame.new
281
+
282
+ @frame.final = (octet & FIN) == FIN
283
+ @frame.rsv1 = rsvs[0]
284
+ @frame.rsv2 = rsvs[1]
285
+ @frame.rsv3 = rsvs[2]
286
+ @frame.opcode = (octet & OPCODE)
287
+
288
+ @stage = 1
289
+
290
+ unless @extensions.valid_frame_rsv?(@frame)
291
+ return fail(:protocol_error,
292
+ "One or more reserved bits are on: reserved1 = #{ @frame.rsv1 ? 1 : 0 }" +
293
+ ", reserved2 = #{ @frame.rsv2 ? 1 : 0 }" +
294
+ ", reserved3 = #{ @frame.rsv3 ? 1 : 0 }")
295
+ end
296
+
297
+ unless OPCODES.values.include?(@frame.opcode)
298
+ return fail(:protocol_error, "Unrecognized frame opcode: #{ @frame.opcode }")
299
+ end
300
+
301
+ unless MESSAGE_OPCODES.include?(@frame.opcode) or @frame.final
302
+ return fail(:protocol_error, "Received fragmented control frame: opcode = #{ @frame.opcode }")
303
+ end
304
+
305
+ if @message and OPENING_OPCODES.include?(@frame.opcode)
306
+ return fail(:protocol_error, 'Received new data frame but previous continuous frame is unfinished')
307
+ end
308
+ end
309
+
310
+ def parse_length(octet)
311
+ @frame.masked = (octet & MASK) == MASK
312
+ @frame.length = (octet & LENGTH)
313
+
314
+ if @frame.length >= 0 and @frame.length <= 125
315
+ @stage = @frame.masked ? 3 : 4
316
+ return unless check_frame_length
317
+ else
318
+ @stage = 2
319
+ @frame.length_bytes = (@frame.length == 126) ? 2 : 8
320
+ end
321
+
322
+ if @require_masking and not @frame.masked
323
+ return fail(:unacceptable, 'Received unmasked frame but masking is required')
324
+ end
325
+ end
326
+
327
+ def parse_extended_length(buffer)
328
+ @frame.length = buffer.unpack(PACK_FORMATS[buffer.bytesize]).first
329
+ @stage = @frame.masked ? 3 : 4
330
+
331
+ unless MESSAGE_OPCODES.include?(@frame.opcode) or @frame.length <= 125
332
+ return fail(:protocol_error, "Received control frame having too long payload: #{ @frame.length }")
333
+ end
334
+
335
+ return unless check_frame_length
336
+ end
337
+
338
+ def check_frame_length
339
+ length = @message ? @message.data.bytesize : 0
340
+
341
+ if length + @frame.length > @max_length
342
+ fail(:too_large, 'WebSocket frame length too large')
343
+ false
344
+ else
345
+ true
346
+ end
347
+ end
348
+
349
+ def emit_frame(buffer)
350
+ frame = @frame
351
+ opcode = frame.opcode
352
+ payload = frame.payload = Mask.mask(buffer, @frame.masking_key)
353
+ bytesize = payload.bytesize
354
+
355
+ @frame = nil
356
+
357
+ case opcode
358
+ when OPCODES[:continuation] then
359
+ return fail(:protocol_error, 'Received unexpected continuation frame') unless @message
360
+ @message << frame
361
+
362
+ when OPCODES[:text], OPCODES[:binary] then
363
+ @message = Message.new
364
+ @message << frame
365
+
366
+ when OPCODES[:close] then
367
+ code, reason = payload.unpack('S>a*') if bytesize >= 2
368
+ reason = Driver.encode(reason || '', Encoding::UTF_8)
369
+
370
+ unless (bytesize == 0) or
371
+ (code && code >= MIN_RESERVED_ERROR && code <= MAX_RESERVED_ERROR) or
372
+ ERROR_CODES.include?(code)
373
+ code = ERRORS[:protocol_error]
374
+ end
375
+
376
+ if bytesize > 125 or !reason.valid_encoding?
377
+ code = ERRORS[:protocol_error]
378
+ end
379
+
380
+ shutdown(code || DEFAULT_ERROR_CODE, reason || '')
381
+
382
+ when OPCODES[:ping] then
383
+ frame(payload, :pong)
384
+ emit(:ping, PingEvent.new(payload))
385
+
386
+ when OPCODES[:pong] then
387
+ message = Driver.encode(payload, Encoding::UTF_8)
388
+ callback = @ping_callbacks[message]
389
+ @ping_callbacks.delete(message)
390
+ callback.call if callback
391
+ emit(:pong, PongEvent.new(payload))
392
+ end
393
+
394
+ emit_message if frame.final and MESSAGE_OPCODES.include?(opcode)
395
+ end
396
+
397
+ def emit_message
398
+ message = @extensions.process_incoming_message(@message)
399
+ @message = nil
400
+
401
+ payload = message.data
402
+
403
+ case message.opcode
404
+ when OPCODES[:text] then
405
+ payload = Driver.encode(payload, Encoding::UTF_8)
406
+ payload = nil unless payload.valid_encoding?
407
+ when OPCODES[:binary]
408
+ if @binary_data_format == :array
409
+ payload = payload.bytes.to_a
410
+ else
411
+ payload = Driver.encode(payload, Encoding::BINARY)
412
+ end
413
+ end
414
+
415
+ if payload
416
+ emit(:message, MessageEvent.new(payload))
417
+ else
418
+ fail(:encoding_error, 'Could not decode a text frame as UTF-8')
419
+ end
420
+ rescue ::WebSocket::Extensions::ExtensionError => error
421
+ fail(:extension_error, error.message)
422
+ end
423
+ end
424
+
425
+ end
426
+ end
@@ -0,0 +1,66 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Proxy
5
+ include EventEmitter
6
+
7
+ attr_reader :status, :headers
8
+
9
+ def initialize(client, origin, options)
10
+ super()
11
+
12
+ @client = client
13
+ @http = HTTP::Response.new
14
+ @socket = client.instance_variable_get(:@socket)
15
+ @origin = URI.parse(@socket.url)
16
+ @url = URI.parse(origin)
17
+ @options = options
18
+ @state = 0
19
+
20
+ @headers = Headers.new
21
+ @headers['Host'] = Driver.host_header(@origin)
22
+ @headers['Connection'] = 'keep-alive'
23
+ @headers['Proxy-Connection'] = 'keep-alive'
24
+
25
+ if @url.user
26
+ auth = Base64.strict_encode64([@url.user, @url.password] * ':')
27
+ @headers['Proxy-Authorization'] = 'Basic ' + auth
28
+ end
29
+ end
30
+
31
+ def set_header(name, value)
32
+ return false unless @state == 0
33
+ @headers[name] = value
34
+ true
35
+ end
36
+
37
+ def start
38
+ return false unless @state == 0
39
+ @state = 1
40
+
41
+ port = @origin.port || PORTS[@origin.scheme]
42
+ start = "CONNECT #{ @origin.host }:#{ port } HTTP/1.1"
43
+ headers = [start, @headers.to_s, '']
44
+
45
+ @socket.write(headers.join("\r\n"))
46
+ true
47
+ end
48
+
49
+ def parse(chunk)
50
+ @http.parse(chunk)
51
+ return unless @http.complete?
52
+
53
+ @status = @http.code
54
+ @headers = Headers.new(@http.headers)
55
+
56
+ if @status == 200
57
+ emit(:connect, ConnectEvent.new)
58
+ else
59
+ message = "Can't establish a connection to the server at #{ @socket.url }"
60
+ emit(:error, ProtocolError.new(message))
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,80 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Server < Driver
5
+ EVENTS = %w[open message error close ping pong]
6
+
7
+ def initialize(socket, options = {})
8
+ super
9
+ @http = HTTP::Request.new
10
+ @delegate = nil
11
+ end
12
+
13
+ def env
14
+ @http.complete? ? @http.env : nil
15
+ end
16
+
17
+ def url
18
+ return nil unless e = env
19
+
20
+ url = "ws://#{ e['HTTP_HOST'] }"
21
+ url << e['PATH_INFO']
22
+ url << "?#{ e['QUERY_STRING'] }" unless e['QUERY_STRING'] == ''
23
+ url
24
+ end
25
+
26
+ %w[add_extension set_header start frame text binary ping close].each do |method|
27
+ define_method(method) do |*args, &block|
28
+ if @delegate
29
+ @delegate.__send__(method, *args, &block)
30
+ else
31
+ @queue << [method, args, block]
32
+ true
33
+ end
34
+ end
35
+ end
36
+
37
+ %w[protocol version].each do |method|
38
+ define_method(method) do
39
+ @delegate && @delegate.__send__(method)
40
+ end
41
+ end
42
+
43
+ def parse(chunk)
44
+ return @delegate.parse(chunk) if @delegate
45
+
46
+ @http.parse(chunk)
47
+ return fail_request('Invalid HTTP request') if @http.error?
48
+ return unless @http.complete?
49
+
50
+ @delegate = Driver.rack(self, @options)
51
+ open
52
+
53
+ EVENTS.each do |event|
54
+ @delegate.on(event) { |e| emit(event, e) }
55
+ end
56
+
57
+ emit(:connect, ConnectEvent.new)
58
+ end
59
+
60
+ def write(buffer)
61
+ @socket.write(buffer)
62
+ end
63
+
64
+ private
65
+
66
+ def fail_request(message)
67
+ emit(:error, ProtocolError.new(message))
68
+ emit(:close, CloseEvent.new(Hybi::ERRORS[:protocol_error], message))
69
+ end
70
+
71
+ def open
72
+ @queue.each do |method, args, block|
73
+ @delegate.__send__(method, *args, &block)
74
+ end
75
+ @queue = []
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,55 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class StreamReader
5
+ # Try to minimise the number of reallocations done:
6
+ MINIMUM_AUTOMATIC_PRUNE_OFFSET = 128
7
+
8
+ def initialize
9
+ @buffer = String.new('').force_encoding(Encoding::BINARY)
10
+ @offset = 0
11
+ end
12
+
13
+ def put(chunk)
14
+ return unless chunk and chunk.bytesize > 0
15
+ @buffer << chunk.force_encoding(Encoding::BINARY)
16
+ end
17
+
18
+ # Read bytes from the data:
19
+ def read(length)
20
+ return nil if (@offset + length) > @buffer.bytesize
21
+
22
+ chunk = @buffer.byteslice(@offset, length)
23
+ @offset += chunk.bytesize
24
+
25
+ prune if @offset > MINIMUM_AUTOMATIC_PRUNE_OFFSET
26
+
27
+ return chunk
28
+ end
29
+
30
+ def each_byte
31
+ prune
32
+
33
+ @buffer.each_byte do |octet|
34
+ @offset += 1
35
+ yield octet
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def prune
42
+ buffer_size = @buffer.bytesize
43
+
44
+ if @offset > buffer_size
45
+ @buffer = String.new('').force_encoding(Encoding::BINARY)
46
+ else
47
+ @buffer = @buffer.byteslice(@offset, buffer_size - @offset)
48
+ end
49
+
50
+ @offset = 0
51
+ end
52
+ end
53
+
54
+ end
55
+ end