websocket-driver 0.5.4-java → 0.6.0-java
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/CHANGELOG.md +7 -0
- data/README.md +26 -16
- data/lib/websocket/driver.rb +6 -0
- data/lib/websocket/driver/client.rb +5 -5
- data/lib/websocket/driver/draft75.rb +4 -2
- data/lib/websocket/driver/event_emitter.rb +8 -4
- data/lib/websocket/driver/hybi.rb +34 -30
- data/lib/websocket/driver/proxy.rb +2 -2
- data/lib/websocket/driver/stream_reader.rb +55 -0
- metadata +3 -3
- data/lib/websocket/driver/hybi/stream_reader.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c10bbc50ea2348fbb23d243ca2c26ca10b7852c
|
4
|
+
data.tar.gz: b4fae4fc45971242b4cd24d142c6abd25818fdb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f53a36ffb90e346faa9662e8fb270b20e3b4ac78eba3c51a1511b432c38bfcfe22ea783eac3a31f035a4d9c65d45f72bbc880ba4c0e71832edc3117614506d78
|
7
|
+
data.tar.gz: 0ad4d8184eeff96b45eb40f308059a84dbe19f12146d10f0edc7496005854e527127e8b26a24b0d526c0a0033c8449dfea91d7e8d3150f3b110dfb8227de7f2f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
### 0.6.0 / 2015-07-08
|
2
|
+
|
3
|
+
* Use `SecureRandom` to generate the `Sec-WebSocket-Key` header
|
4
|
+
* Allow the parser to recover cleanly if event listeners raise an error
|
5
|
+
* Let the `on()` method take a lambda as a positional argument rather than a block
|
6
|
+
* Add a `pong` method for sending unsolicited pong frames
|
7
|
+
|
1
8
|
### 0.5.4 / 2015-03-29
|
2
9
|
|
3
10
|
* Don't emit extra close frames if we receive a close frame after we already
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ this module up to some I/O object, it will do all of this for you:
|
|
21
21
|
* Deal with proxies that defer delivery of the draft-76 handshake body
|
22
22
|
* Notify you when the socket is open and closed and when messages arrive
|
23
23
|
* Recombine fragmented messages
|
24
|
-
* Dispatch text, binary, ping and close frames
|
24
|
+
* Dispatch text, binary, ping, pong and close frames
|
25
25
|
* Manage the socket-closing handshake process
|
26
26
|
* Automatically reply to ping frames with a matching pong
|
27
27
|
* Apply masking to messages sent by the client
|
@@ -54,6 +54,7 @@ Server-side sockets require one additional method:
|
|
54
54
|
* `HTTP_CONNECTION`
|
55
55
|
* `HTTP_HOST`
|
56
56
|
* `HTTP_ORIGIN`
|
57
|
+
* `HTTP_SEC_WEBSOCKET_EXTENSIONS`
|
57
58
|
* `HTTP_SEC_WEBSOCKET_KEY`
|
58
59
|
* `HTTP_SEC_WEBSOCKET_KEY1`
|
59
60
|
* `HTTP_SEC_WEBSOCKET_KEY2`
|
@@ -145,7 +146,7 @@ module Connection
|
|
145
146
|
def initialize
|
146
147
|
@driver = WebSocket::Driver.server(self)
|
147
148
|
|
148
|
-
@driver.on
|
149
|
+
@driver.on :connect, -> (event) do
|
149
150
|
if WebSocket::Driver.websocket?(@driver.env)
|
150
151
|
@driver.start
|
151
152
|
else
|
@@ -153,8 +154,8 @@ module Connection
|
|
153
154
|
end
|
154
155
|
end
|
155
156
|
|
156
|
-
@driver.on
|
157
|
-
@driver.on
|
157
|
+
@driver.on :message, -> (e) { @driver.text(e.data) }
|
158
|
+
@driver.on :close, -> (e) { close_connection_after_writing }
|
158
159
|
end
|
159
160
|
|
160
161
|
def receive_data(data)
|
@@ -213,7 +214,7 @@ start sending incoming data to `driver.parse(data)` as normal, and call
|
|
213
214
|
```rb
|
214
215
|
proxy = driver.proxy('http://username:password@proxy.example.com')
|
215
216
|
|
216
|
-
proxy.on :connect do
|
217
|
+
proxy.on :connect, -> (event) do
|
217
218
|
driver.start
|
218
219
|
end
|
219
220
|
```
|
@@ -225,7 +226,7 @@ In the event that proxy connection fails, `proxy` will emit an `:error`. You can
|
|
225
226
|
inspect the proxy's response via `proxy.status` and `proxy.headers`.
|
226
227
|
|
227
228
|
```rb
|
228
|
-
proxy.on :error
|
229
|
+
proxy.on :error, -> (error) do
|
229
230
|
puts error.message
|
230
231
|
puts proxy.status
|
231
232
|
puts proxy.headers.inspect
|
@@ -273,25 +274,25 @@ Note that most of these methods are commands: if they produce data that should
|
|
273
274
|
be sent over the socket, they will give this to you by calling
|
274
275
|
`socket.write(string)`.
|
275
276
|
|
276
|
-
#### `driver.on
|
277
|
+
#### `driver.on 'open', -> (event) { }`
|
277
278
|
|
278
|
-
|
279
|
+
Adds a callback block to execute when the socket becomes open.
|
279
280
|
|
280
|
-
#### `driver.on
|
281
|
+
#### `driver.on 'message', -> (event) { }`
|
281
282
|
|
282
|
-
|
283
|
-
|
284
|
-
|
283
|
+
Adds a callback block to execute when a message is received. `event` will have a
|
284
|
+
`data` attribute containing either a string in the case of a text message or an
|
285
|
+
array of integers in the case of a binary message.
|
285
286
|
|
286
|
-
#### `driver.on
|
287
|
+
#### `driver.on 'error', -> (event) { }`
|
287
288
|
|
288
|
-
|
289
|
+
Adds a callback to execute when a protocol error occurs due to the other peer
|
289
290
|
sending an invalid byte sequence. `event` will have a `message` attribute
|
290
291
|
describing the error.
|
291
292
|
|
292
|
-
#### `driver.on
|
293
|
+
#### `driver.on 'close', -> (event) { }`
|
293
294
|
|
294
|
-
|
295
|
+
Adds a callback block to execute when the socket becomes closed. The `event`
|
295
296
|
object has `code` and `reason` attributes.
|
296
297
|
|
297
298
|
#### `driver.add_extension(extension)`
|
@@ -339,6 +340,15 @@ when the socket receives a pong frame whose content matches `string`. Returns
|
|
339
340
|
`false` if frames can no longer be sent, or if the driver does not support
|
340
341
|
ping/pong.
|
341
342
|
|
343
|
+
#### `driver.pong(string = '')`
|
344
|
+
|
345
|
+
Sends a pong frame over the socket, queueing it if necessary. `string` is
|
346
|
+
optional. Returns `false` if frames can no longer be sent, or if the driver does
|
347
|
+
not support ping/pong.
|
348
|
+
|
349
|
+
You don't need to call this when a ping frame is received; pings are replied to
|
350
|
+
automatically by the driver. This method is for sending unsolicited pongs.
|
351
|
+
|
342
352
|
#### `driver.close`
|
343
353
|
|
344
354
|
Initiates the closing handshake if the socket is still open. For drivers with no
|
data/lib/websocket/driver.rb
CHANGED
@@ -56,6 +56,7 @@ module WebSocket
|
|
56
56
|
autoload :Hybi, root + '/hybi'
|
57
57
|
autoload :Proxy, root + '/proxy'
|
58
58
|
autoload :Server, root + '/server'
|
59
|
+
autoload :StreamReader, root + '/stream_reader'
|
59
60
|
|
60
61
|
include EventEmitter
|
61
62
|
attr_reader :protocol, :ready_state
|
@@ -65,6 +66,7 @@ module WebSocket
|
|
65
66
|
Driver.validate_options(options, [:max_length, :masking, :require_masking, :protocols])
|
66
67
|
|
67
68
|
@socket = socket
|
69
|
+
@reader = StreamReader.new
|
68
70
|
@options = options
|
69
71
|
@max_length = options[:max_length] || MAX_LENGTH
|
70
72
|
@headers = Headers.new
|
@@ -108,6 +110,10 @@ module WebSocket
|
|
108
110
|
false
|
109
111
|
end
|
110
112
|
|
113
|
+
def pong(*args)
|
114
|
+
false
|
115
|
+
end
|
116
|
+
|
111
117
|
def close(reason = nil, code = nil)
|
112
118
|
return false unless @ready_state == 1
|
113
119
|
@ready_state = 3
|
@@ -3,7 +3,7 @@ module WebSocket
|
|
3
3
|
|
4
4
|
class Client < Hybi
|
5
5
|
def self.generate_key
|
6
|
-
Base64.
|
6
|
+
Base64.strict_encode64(SecureRandom.random_bytes(16))
|
7
7
|
end
|
8
8
|
|
9
9
|
attr_reader :status, :headers
|
@@ -32,7 +32,7 @@ module WebSocket
|
|
32
32
|
end
|
33
33
|
|
34
34
|
if uri.user
|
35
|
-
auth = Base64.
|
35
|
+
auth = Base64.strict_encode64([uri.user, uri.password] * ':')
|
36
36
|
@headers['Authorization'] = 'Basic ' + auth
|
37
37
|
end
|
38
38
|
end
|
@@ -80,8 +80,8 @@ module WebSocket
|
|
80
80
|
|
81
81
|
def fail_handshake(message)
|
82
82
|
message = "Error during WebSocket handshake: #{message}"
|
83
|
-
emit(:error, ProtocolError.new(message))
|
84
83
|
@ready_state = 3
|
84
|
+
emit(:error, ProtocolError.new(message))
|
85
85
|
emit(:close, CloseEvent.new(ERRORS[:protocol_error], message))
|
86
86
|
end
|
87
87
|
|
@@ -124,8 +124,8 @@ module WebSocket
|
|
124
124
|
|
125
125
|
begin
|
126
126
|
@extensions.activate(@headers['Sec-WebSocket-Extensions'])
|
127
|
-
rescue ::WebSocket::Extensions::ExtensionError =>
|
128
|
-
return fail_handshake(
|
127
|
+
rescue ::WebSocket::Extensions::ExtensionError => error
|
128
|
+
return fail_handshake(error.message)
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
@@ -26,7 +26,9 @@ module WebSocket
|
|
26
26
|
def parse(buffer)
|
27
27
|
return if @ready_state > 1
|
28
28
|
|
29
|
-
buffer
|
29
|
+
@reader.put(buffer)
|
30
|
+
|
31
|
+
@reader.each_byte do |data|
|
30
32
|
case @stage
|
31
33
|
when -1 then
|
32
34
|
@body << data
|
@@ -52,8 +54,8 @@ module WebSocket
|
|
52
54
|
|
53
55
|
when 2 then
|
54
56
|
if data == 0xFF
|
55
|
-
emit(:message, MessageEvent.new(Driver.encode(@buffer, :utf8)))
|
56
57
|
@stage = 0
|
58
|
+
emit(:message, MessageEvent.new(Driver.encode(@buffer, :utf8)))
|
57
59
|
else
|
58
60
|
if @length
|
59
61
|
@skipped += 1
|
@@ -6,16 +6,20 @@ module WebSocket
|
|
6
6
|
@listeners = Hash.new { |h,k| h[k] = [] }
|
7
7
|
end
|
8
8
|
|
9
|
-
def add_listener(event, &
|
9
|
+
def add_listener(event, callable = nil, &block)
|
10
|
+
listener = callable || block
|
10
11
|
@listeners[event.to_s] << listener
|
12
|
+
listener
|
11
13
|
end
|
12
14
|
|
13
|
-
def on(event, &
|
14
|
-
add_listener(event, &
|
15
|
+
def on(event, callable = nil, &block)
|
16
|
+
add_listener(event, callable, &block)
|
15
17
|
end
|
16
18
|
|
17
|
-
def remove_listener(event, &
|
19
|
+
def remove_listener(event, callable = nil, &block)
|
20
|
+
listener = callable || block
|
18
21
|
@listeners[event.to_s].delete(listener)
|
22
|
+
listener
|
19
23
|
end
|
20
24
|
|
21
25
|
def remove_all_listeners(event = nil)
|
@@ -4,12 +4,11 @@ module WebSocket
|
|
4
4
|
class Hybi < Driver
|
5
5
|
root = File.expand_path('../hybi', __FILE__)
|
6
6
|
|
7
|
-
autoload :Frame,
|
8
|
-
autoload :Message,
|
9
|
-
autoload :StreamReader, root + '/stream_reader'
|
7
|
+
autoload :Frame, root + '/frame'
|
8
|
+
autoload :Message, root + '/message'
|
10
9
|
|
11
10
|
def self.generate_accept(key)
|
12
|
-
Base64.
|
11
|
+
Base64.strict_encode64(Digest::SHA1.digest(key + GUID))
|
13
12
|
end
|
14
13
|
|
15
14
|
GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
|
@@ -55,7 +54,6 @@ module WebSocket
|
|
55
54
|
super
|
56
55
|
|
57
56
|
@extensions = ::WebSocket::Extensions.new
|
58
|
-
@reader = StreamReader.new
|
59
57
|
@stage = 0
|
60
58
|
@masking = options[:masking]
|
61
59
|
@protocols = options[:protocols] || []
|
@@ -108,15 +106,16 @@ module WebSocket
|
|
108
106
|
when 3 then
|
109
107
|
buffer = @reader.read(4)
|
110
108
|
if buffer
|
111
|
-
@frame.masking_key = buffer
|
112
109
|
@stage = 4
|
110
|
+
@frame.masking_key = buffer
|
113
111
|
end
|
114
112
|
|
115
113
|
when 4 then
|
116
114
|
buffer = @reader.read(@frame.length)
|
115
|
+
|
117
116
|
if buffer
|
118
|
-
emit_frame(buffer)
|
119
117
|
@stage = 0
|
118
|
+
emit_frame(buffer)
|
120
119
|
end
|
121
120
|
|
122
121
|
else
|
@@ -138,6 +137,10 @@ module WebSocket
|
|
138
137
|
frame(message, :ping)
|
139
138
|
end
|
140
139
|
|
140
|
+
def pong(message = '')
|
141
|
+
frame(message, :pong)
|
142
|
+
end
|
143
|
+
|
141
144
|
def close(reason = nil, code = nil)
|
142
145
|
reason ||= ''
|
143
146
|
code ||= ERRORS[:normal_closure]
|
@@ -188,6 +191,9 @@ module WebSocket
|
|
188
191
|
|
189
192
|
send_frame(frame)
|
190
193
|
true
|
194
|
+
|
195
|
+
rescue ::WebSocket::Extensions::ExtensionError => error
|
196
|
+
fail(:extension_error, error.message)
|
191
197
|
end
|
192
198
|
|
193
199
|
private
|
@@ -231,16 +237,13 @@ module WebSocket
|
|
231
237
|
end
|
232
238
|
|
233
239
|
@socket.write(buffer.pack('C*'))
|
234
|
-
|
235
|
-
rescue ::WebSocket::Extensions::ExtensionError => e
|
236
|
-
fail(:extension_error, e.message)
|
237
240
|
end
|
238
241
|
|
239
242
|
def handshake_response
|
240
243
|
begin
|
241
244
|
extensions = @extensions.generate_response(@socket.env['HTTP_SEC_WEBSOCKET_EXTENSIONS'])
|
242
|
-
rescue =>
|
243
|
-
fail(:protocol_error,
|
245
|
+
rescue => error
|
246
|
+
fail(:protocol_error, error.message)
|
244
247
|
return nil
|
245
248
|
end
|
246
249
|
|
@@ -251,19 +254,21 @@ module WebSocket
|
|
251
254
|
headers.join("\r\n")
|
252
255
|
end
|
253
256
|
|
254
|
-
def shutdown(code, reason)
|
255
|
-
frame(reason, :close, code) if @ready_state < 2
|
257
|
+
def shutdown(code, reason, error = false)
|
256
258
|
@frame = @message = nil
|
257
|
-
@ready_state = 3
|
258
259
|
@stage = 5
|
259
|
-
emit(:close, CloseEvent.new(code, reason))
|
260
260
|
@extensions.close
|
261
|
+
|
262
|
+
frame(reason, :close, code) if @ready_state < 2
|
263
|
+
@ready_state = 3
|
264
|
+
|
265
|
+
emit(:error, ProtocolError.new(reason)) if error
|
266
|
+
emit(:close, CloseEvent.new(code, reason))
|
261
267
|
end
|
262
268
|
|
263
269
|
def fail(type, message)
|
264
270
|
return if @ready_state > 1
|
265
|
-
|
266
|
-
shutdown(ERRORS[type], message)
|
271
|
+
shutdown(ERRORS[type], message, true)
|
267
272
|
end
|
268
273
|
|
269
274
|
def parse_opcode(data)
|
@@ -277,6 +282,8 @@ module WebSocket
|
|
277
282
|
@frame.rsv3 = rsvs[2]
|
278
283
|
@frame.opcode = (data & OPCODE)
|
279
284
|
|
285
|
+
@stage = 1
|
286
|
+
|
280
287
|
unless @extensions.valid_frame_rsv?(@frame)
|
281
288
|
return fail(:protocol_error,
|
282
289
|
"One or more reserved bits are on: reserved1 = #{@frame.rsv1 ? 1 : 0}" +
|
@@ -295,37 +302,34 @@ module WebSocket
|
|
295
302
|
if @message and OPENING_OPCODES.include?(@frame.opcode)
|
296
303
|
return fail(:protocol_error, 'Received new data frame but previous continuous frame is unfinished')
|
297
304
|
end
|
298
|
-
|
299
|
-
@stage = 1
|
300
305
|
end
|
301
306
|
|
302
307
|
def parse_length(data)
|
303
308
|
@frame.masked = (data & MASK) == MASK
|
304
|
-
if @require_masking and not @frame.masked
|
305
|
-
return fail(:unacceptable, 'Received unmasked frame but masking is required')
|
306
|
-
end
|
307
|
-
|
308
309
|
@frame.length = (data & LENGTH)
|
309
310
|
|
310
311
|
if @frame.length >= 0 and @frame.length <= 125
|
311
|
-
return unless check_frame_length
|
312
312
|
@stage = @frame.masked ? 3 : 4
|
313
|
+
return unless check_frame_length
|
313
314
|
else
|
314
|
-
@frame.length_bytes = (@frame.length == 126) ? 2 : 8
|
315
315
|
@stage = 2
|
316
|
+
@frame.length_bytes = (@frame.length == 126) ? 2 : 8
|
317
|
+
end
|
318
|
+
|
319
|
+
if @require_masking and not @frame.masked
|
320
|
+
return fail(:unacceptable, 'Received unmasked frame but masking is required')
|
316
321
|
end
|
317
322
|
end
|
318
323
|
|
319
324
|
def parse_extended_length(buffer)
|
320
325
|
@frame.length = integer(buffer)
|
326
|
+
@stage = @frame.masked ? 3 : 4
|
321
327
|
|
322
328
|
unless MESSAGE_OPCODES.include?(@frame.opcode) or @frame.length <= 125
|
323
329
|
return fail(:protocol_error, "Received control frame having too long payload: #{@frame.length}")
|
324
330
|
end
|
325
331
|
|
326
332
|
return unless check_frame_length
|
327
|
-
|
328
|
-
@stage = @frame.masked ? 3 : 4
|
329
333
|
end
|
330
334
|
|
331
335
|
def check_frame_length
|
@@ -404,8 +408,8 @@ module WebSocket
|
|
404
408
|
else
|
405
409
|
fail(:encoding_error, 'Could not decode a text frame as UTF-8')
|
406
410
|
end
|
407
|
-
rescue ::WebSocket::Extensions::ExtensionError =>
|
408
|
-
fail(:extension_error,
|
411
|
+
rescue ::WebSocket::Extensions::ExtensionError => error
|
412
|
+
fail(:extension_error, error.message)
|
409
413
|
end
|
410
414
|
|
411
415
|
def integer(buffer)
|
@@ -25,7 +25,7 @@ module WebSocket
|
|
25
25
|
@headers['Proxy-Connection'] = 'keep-alive'
|
26
26
|
|
27
27
|
if @url.user
|
28
|
-
auth = Base64.
|
28
|
+
auth = Base64.strict_encode64([@url.user, @url.password] * ':')
|
29
29
|
@headers['Proxy-Authorization'] = 'Basic ' + auth
|
30
30
|
end
|
31
31
|
end
|
@@ -56,7 +56,7 @@ module WebSocket
|
|
56
56
|
@headers = Headers.new(@http.headers)
|
57
57
|
|
58
58
|
if @status == 200
|
59
|
-
emit(:connect)
|
59
|
+
emit(:connect, ConnectEvent.new)
|
60
60
|
else
|
61
61
|
message = "Can't establish a connection to the server at #{@socket.url}"
|
62
62
|
emit(:error, ProtocolError.new(message))
|
@@ -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 = Driver.encode('', :binary)
|
10
|
+
@offset = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def put(buffer)
|
14
|
+
return unless buffer and buffer.bytesize > 0
|
15
|
+
@buffer << Driver.encode(buffer, :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 |value|
|
34
|
+
@offset += 1
|
35
|
+
yield value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def prune
|
42
|
+
buffer_size = @buffer.bytesize
|
43
|
+
|
44
|
+
if @offset > buffer_size
|
45
|
+
@buffer = Driver.encode('', :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
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: websocket-driver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- James Coglan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: websocket-extensions
|
@@ -102,9 +102,9 @@ files:
|
|
102
102
|
- lib/websocket/driver/hybi.rb
|
103
103
|
- lib/websocket/driver/hybi/frame.rb
|
104
104
|
- lib/websocket/driver/hybi/message.rb
|
105
|
-
- lib/websocket/driver/hybi/stream_reader.rb
|
106
105
|
- lib/websocket/driver/proxy.rb
|
107
106
|
- lib/websocket/driver/server.rb
|
107
|
+
- lib/websocket/driver/stream_reader.rb
|
108
108
|
- lib/websocket/driver/utf8_match.rb
|
109
109
|
- lib/websocket/http.rb
|
110
110
|
- lib/websocket/http/headers.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module WebSocket
|
2
|
-
class Driver
|
3
|
-
|
4
|
-
class Hybi
|
5
|
-
class StreamReader
|
6
|
-
def initialize
|
7
|
-
@buffer = Driver.encode('', :binary)
|
8
|
-
end
|
9
|
-
|
10
|
-
def put(string)
|
11
|
-
return unless string and string.bytesize > 0
|
12
|
-
@buffer << Driver.encode(string, :binary)
|
13
|
-
end
|
14
|
-
|
15
|
-
def read(length)
|
16
|
-
buffer_size = @buffer.bytesize
|
17
|
-
return nil if length > buffer_size
|
18
|
-
|
19
|
-
chunk = @buffer.byteslice(0, length)
|
20
|
-
@buffer = @buffer.byteslice(length, buffer_size - length)
|
21
|
-
|
22
|
-
chunk
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|