faye-websocket 0.4.7 → 0.5.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.
Potentially problematic release.
This version of faye-websocket might be problematic. Click here for more details.
- data/CHANGELOG.md +81 -0
- data/README.md +408 -0
- data/examples/app.rb +4 -1
- data/examples/autobahn_client.rb +8 -6
- data/examples/client.rb +2 -1
- data/examples/config.ru +6 -9
- data/{spec → examples}/rainbows.conf +0 -0
- data/examples/server.rb +10 -1
- data/lib/faye/adapters/rainbows.rb +15 -16
- data/lib/faye/adapters/rainbows_client.rb +15 -16
- data/lib/faye/adapters/thin.rb +15 -16
- data/lib/faye/eventsource.rb +38 -46
- data/lib/faye/rack_stream.rb +70 -0
- data/lib/faye/websocket.rb +39 -162
- data/lib/faye/websocket/api.rb +70 -60
- data/lib/faye/websocket/api/event.rb +1 -1
- data/lib/faye/websocket/api/event_target.rb +35 -12
- data/lib/faye/websocket/client.rb +5 -38
- metadata +62 -45
- data/CHANGELOG.txt +0 -74
- data/README.rdoc +0 -366
- data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +0 -61
- data/ext/faye_websocket_mask/extconf.rb +0 -5
- data/ext/faye_websocket_mask/faye_websocket_mask.c +0 -33
- data/lib/faye/websocket/draft75_parser.rb +0 -87
- data/lib/faye/websocket/draft76_parser.rb +0 -84
- data/lib/faye/websocket/hybi_parser.rb +0 -321
- data/lib/faye/websocket/hybi_parser/handshake.rb +0 -78
- data/lib/faye/websocket/hybi_parser/stream_reader.rb +0 -29
- data/lib/faye/websocket/utf8_match.rb +0 -8
- data/spec/faye/websocket/client_spec.rb +0 -162
- data/spec/faye/websocket/draft75_parser_examples.rb +0 -48
- data/spec/faye/websocket/draft75_parser_spec.rb +0 -27
- data/spec/faye/websocket/draft76_parser_spec.rb +0 -34
- data/spec/faye/websocket/hybi_parser_spec.rb +0 -149
- data/spec/server.crt +0 -15
- data/spec/server.key +0 -15
- data/spec/spec_helper.rb +0 -68
@@ -1,61 +0,0 @@
|
|
1
|
-
package com.jcoglan.faye;
|
2
|
-
|
3
|
-
import java.lang.Long;
|
4
|
-
import java.io.IOException;
|
5
|
-
|
6
|
-
import org.jruby.Ruby;
|
7
|
-
import org.jruby.RubyArray;
|
8
|
-
import org.jruby.RubyClass;
|
9
|
-
import org.jruby.RubyFixnum;
|
10
|
-
import org.jruby.RubyModule;
|
11
|
-
import org.jruby.RubyObject;
|
12
|
-
import org.jruby.anno.JRubyMethod;
|
13
|
-
import org.jruby.runtime.ObjectAllocator;
|
14
|
-
import org.jruby.runtime.ThreadContext;
|
15
|
-
import org.jruby.runtime.builtin.IRubyObject;
|
16
|
-
import org.jruby.runtime.load.BasicLibraryService;
|
17
|
-
|
18
|
-
public class FayeWebsocketMaskService implements BasicLibraryService {
|
19
|
-
private Ruby runtime;
|
20
|
-
|
21
|
-
public boolean basicLoad(Ruby runtime) throws IOException {
|
22
|
-
this.runtime = runtime;
|
23
|
-
RubyModule faye = runtime.defineModule("Faye");
|
24
|
-
|
25
|
-
RubyClass webSocketMask = faye.defineClassUnder("WebSocketMask", runtime.getObject(), new ObjectAllocator() {
|
26
|
-
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
|
27
|
-
return new WebsocketMask(runtime, rubyClass);
|
28
|
-
}
|
29
|
-
});
|
30
|
-
|
31
|
-
webSocketMask.defineAnnotatedMethods(WebsocketMask.class);
|
32
|
-
return true;
|
33
|
-
}
|
34
|
-
|
35
|
-
public class WebsocketMask extends RubyObject {
|
36
|
-
public WebsocketMask(final Ruby runtime, RubyClass rubyClass) {
|
37
|
-
super(runtime, rubyClass);
|
38
|
-
}
|
39
|
-
|
40
|
-
@JRubyMethod
|
41
|
-
public IRubyObject mask(ThreadContext context, IRubyObject payload, IRubyObject mask) {
|
42
|
-
int n = ((RubyArray)payload).getLength(), i;
|
43
|
-
long p, m;
|
44
|
-
RubyArray unmasked = RubyArray.newArray(runtime, n);
|
45
|
-
|
46
|
-
long[] maskArray = {
|
47
|
-
(Long)((RubyArray)mask).get(0),
|
48
|
-
(Long)((RubyArray)mask).get(1),
|
49
|
-
(Long)((RubyArray)mask).get(2),
|
50
|
-
(Long)((RubyArray)mask).get(3)
|
51
|
-
};
|
52
|
-
|
53
|
-
for (i = 0; i < n; i++) {
|
54
|
-
p = (Long)((RubyArray)payload).get(i);
|
55
|
-
m = maskArray[i % 4];
|
56
|
-
unmasked.set(i, p ^ m);
|
57
|
-
}
|
58
|
-
return unmasked;
|
59
|
-
}
|
60
|
-
}
|
61
|
-
}
|
@@ -1,33 +0,0 @@
|
|
1
|
-
#include <ruby.h>
|
2
|
-
|
3
|
-
VALUE Faye = Qnil;
|
4
|
-
VALUE FayeWebSocketMask = Qnil;
|
5
|
-
|
6
|
-
void Init_faye_websocket_mask();
|
7
|
-
VALUE method_faye_websocket_mask(VALUE self, VALUE payload, VALUE mask);
|
8
|
-
|
9
|
-
void Init_faye_websocket_mask() {
|
10
|
-
Faye = rb_define_module("Faye");
|
11
|
-
FayeWebSocketMask = rb_define_module_under(Faye, "WebSocketMask");
|
12
|
-
rb_define_singleton_method(FayeWebSocketMask, "mask", method_faye_websocket_mask, 2);
|
13
|
-
}
|
14
|
-
|
15
|
-
VALUE method_faye_websocket_mask(VALUE self, VALUE payload, VALUE mask) {
|
16
|
-
int n = RARRAY_LEN(payload), i, p, m;
|
17
|
-
VALUE unmasked = rb_ary_new2(n);
|
18
|
-
|
19
|
-
int mask_array[] = {
|
20
|
-
NUM2INT(rb_ary_entry(mask, 0)),
|
21
|
-
NUM2INT(rb_ary_entry(mask, 1)),
|
22
|
-
NUM2INT(rb_ary_entry(mask, 2)),
|
23
|
-
NUM2INT(rb_ary_entry(mask, 3))
|
24
|
-
};
|
25
|
-
|
26
|
-
for (i = 0; i < n; i++) {
|
27
|
-
p = NUM2INT(rb_ary_entry(payload, i));
|
28
|
-
m = mask_array[i % 4];
|
29
|
-
rb_ary_store(unmasked, i, INT2NUM(p ^ m));
|
30
|
-
}
|
31
|
-
return unmasked;
|
32
|
-
}
|
33
|
-
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class Draft75Parser
|
5
|
-
attr_reader :protocol
|
6
|
-
|
7
|
-
def initialize(web_socket, options = {})
|
8
|
-
@socket = web_socket
|
9
|
-
@stage = 0
|
10
|
-
end
|
11
|
-
|
12
|
-
def version
|
13
|
-
'hixie-75'
|
14
|
-
end
|
15
|
-
|
16
|
-
def handshake_response
|
17
|
-
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
18
|
-
upgrade << "Upgrade: WebSocket\r\n"
|
19
|
-
upgrade << "Connection: Upgrade\r\n"
|
20
|
-
upgrade << "WebSocket-Origin: #{@socket.env['HTTP_ORIGIN']}\r\n"
|
21
|
-
upgrade << "WebSocket-Location: #{@socket.url}\r\n"
|
22
|
-
upgrade << "\r\n"
|
23
|
-
upgrade
|
24
|
-
end
|
25
|
-
|
26
|
-
def open?
|
27
|
-
true
|
28
|
-
end
|
29
|
-
|
30
|
-
def parse(buffer)
|
31
|
-
buffer.each_byte do |data|
|
32
|
-
case @stage
|
33
|
-
when 0 then
|
34
|
-
parse_leading_byte(data)
|
35
|
-
|
36
|
-
when 1 then
|
37
|
-
value = (data & 0x7F)
|
38
|
-
@length = value + 128 * @length
|
39
|
-
|
40
|
-
if @closing and @length.zero?
|
41
|
-
@socket.close(nil, nil, false)
|
42
|
-
elsif (0x80 & data) != 0x80
|
43
|
-
if @length.zero?
|
44
|
-
@socket.receive('')
|
45
|
-
@stage = 0
|
46
|
-
else
|
47
|
-
@buffer = []
|
48
|
-
@stage = 2
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
when 2 then
|
53
|
-
if data == 0xFF
|
54
|
-
@socket.receive(WebSocket.encode(@buffer))
|
55
|
-
@stage = 0
|
56
|
-
else
|
57
|
-
@buffer << data
|
58
|
-
if @length and @buffer.size == @length
|
59
|
-
@stage = 0
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
nil
|
66
|
-
end
|
67
|
-
|
68
|
-
def parse_leading_byte(data)
|
69
|
-
if (0x80 & data) == 0x80
|
70
|
-
@length = 0
|
71
|
-
@stage = 1
|
72
|
-
else
|
73
|
-
@length = nil
|
74
|
-
@buffer = []
|
75
|
-
@stage = 2
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def frame(data, type = nil, error_type = nil)
|
80
|
-
return WebSocket.encode(data) if Array === data
|
81
|
-
["\x00", data, "\xFF"].map(&WebSocket.method(:encode)) * ''
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
@@ -1,84 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class Draft76Parser < Draft75Parser
|
5
|
-
def version
|
6
|
-
'hixie-76'
|
7
|
-
end
|
8
|
-
|
9
|
-
def handshake_response
|
10
|
-
env = @socket.env
|
11
|
-
signature = handshake_signature(env['rack.input'].read)
|
12
|
-
|
13
|
-
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
14
|
-
upgrade << "Upgrade: WebSocket\r\n"
|
15
|
-
upgrade << "Connection: Upgrade\r\n"
|
16
|
-
upgrade << "Sec-WebSocket-Origin: #{env['HTTP_ORIGIN']}\r\n"
|
17
|
-
upgrade << "Sec-WebSocket-Location: #{@socket.url}\r\n"
|
18
|
-
upgrade << "\r\n"
|
19
|
-
upgrade << signature if signature
|
20
|
-
upgrade
|
21
|
-
end
|
22
|
-
|
23
|
-
def handshake_signature(head)
|
24
|
-
return nil if head.empty?
|
25
|
-
env = @socket.env
|
26
|
-
|
27
|
-
key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
|
28
|
-
value1 = number_from_key(key1) / spaces_in_key(key1)
|
29
|
-
|
30
|
-
key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
|
31
|
-
value2 = number_from_key(key2) / spaces_in_key(key2)
|
32
|
-
|
33
|
-
@handshake_complete = true
|
34
|
-
|
35
|
-
Digest::MD5.digest(big_endian(value1) +
|
36
|
-
big_endian(value2) +
|
37
|
-
head)
|
38
|
-
end
|
39
|
-
|
40
|
-
def open?
|
41
|
-
!!@handshake_complete
|
42
|
-
end
|
43
|
-
|
44
|
-
def parse(data)
|
45
|
-
return super if @handshake_complete
|
46
|
-
handshake_signature(data)
|
47
|
-
end
|
48
|
-
|
49
|
-
def close(code = nil, reason = nil, &callback)
|
50
|
-
return if @closed
|
51
|
-
@socket.send([0xFF, 0x00]) if @closing
|
52
|
-
@closed = true
|
53
|
-
callback.call if callback
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def parse_leading_byte(data)
|
59
|
-
return super unless data == 0xFF
|
60
|
-
@closing = true
|
61
|
-
@length = 0
|
62
|
-
@stage = 1
|
63
|
-
end
|
64
|
-
|
65
|
-
def number_from_key(key)
|
66
|
-
key.scan(/[0-9]/).join('').to_i(10)
|
67
|
-
end
|
68
|
-
|
69
|
-
def spaces_in_key(key)
|
70
|
-
key.scan(/ /).size
|
71
|
-
end
|
72
|
-
|
73
|
-
def big_endian(number)
|
74
|
-
string = ''
|
75
|
-
[24,16,8,0].each do |offset|
|
76
|
-
string << (number >> offset & 0xFF).chr
|
77
|
-
end
|
78
|
-
string
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
@@ -1,321 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class HybiParser
|
5
|
-
root = File.expand_path('../hybi_parser', __FILE__)
|
6
|
-
autoload :Handshake, root + '/handshake'
|
7
|
-
autoload :StreamReader, root + '/stream_reader'
|
8
|
-
|
9
|
-
BYTE = 0b11111111
|
10
|
-
FIN = MASK = 0b10000000
|
11
|
-
RSV1 = 0b01000000
|
12
|
-
RSV2 = 0b00100000
|
13
|
-
RSV3 = 0b00010000
|
14
|
-
OPCODE = 0b00001111
|
15
|
-
LENGTH = 0b01111111
|
16
|
-
|
17
|
-
OPCODES = {
|
18
|
-
:continuation => 0,
|
19
|
-
:text => 1,
|
20
|
-
:binary => 2,
|
21
|
-
:close => 8,
|
22
|
-
:ping => 9,
|
23
|
-
:pong => 10
|
24
|
-
}
|
25
|
-
|
26
|
-
FRAGMENTED_OPCODES = OPCODES.values_at(:continuation, :text, :binary)
|
27
|
-
OPENING_OPCODES = OPCODES.values_at(:text, :binary)
|
28
|
-
|
29
|
-
ERRORS = {
|
30
|
-
:normal_closure => 1000,
|
31
|
-
:going_away => 1001,
|
32
|
-
:protocol_error => 1002,
|
33
|
-
:unacceptable => 1003,
|
34
|
-
:encoding_error => 1007,
|
35
|
-
:policy_violation => 1008,
|
36
|
-
:too_large => 1009,
|
37
|
-
:extension_error => 1010,
|
38
|
-
:unexpected_condition => 1011
|
39
|
-
}
|
40
|
-
|
41
|
-
ERROR_CODES = ERRORS.values
|
42
|
-
|
43
|
-
attr_reader :protocol
|
44
|
-
|
45
|
-
def initialize(web_socket, options = {})
|
46
|
-
reset
|
47
|
-
@socket = web_socket
|
48
|
-
@reader = StreamReader.new
|
49
|
-
@stage = 0
|
50
|
-
@masking = options[:masking]
|
51
|
-
@protocols = options[:protocols]
|
52
|
-
@protocols = @protocols.split(/\s*,\s*/) if String === @protocols
|
53
|
-
|
54
|
-
@ping_callbacks = {}
|
55
|
-
end
|
56
|
-
|
57
|
-
def version
|
58
|
-
"hybi-#{@socket.env['HTTP_SEC_WEBSOCKET_VERSION']}"
|
59
|
-
end
|
60
|
-
|
61
|
-
def handshake_response
|
62
|
-
sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
|
63
|
-
return '' unless String === sec_key
|
64
|
-
|
65
|
-
accept = Base64.encode64(Digest::SHA1.digest(sec_key + Handshake::GUID)).strip
|
66
|
-
protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
|
67
|
-
supported = @protocols
|
68
|
-
proto = nil
|
69
|
-
|
70
|
-
headers = [
|
71
|
-
"HTTP/1.1 101 Switching Protocols",
|
72
|
-
"Upgrade: websocket",
|
73
|
-
"Connection: Upgrade",
|
74
|
-
"Sec-WebSocket-Accept: #{accept}"
|
75
|
-
]
|
76
|
-
|
77
|
-
if protos and supported
|
78
|
-
protos = protos.split(/\s*,\s*/) if String === protos
|
79
|
-
proto = protos.find { |p| supported.include?(p) }
|
80
|
-
if proto
|
81
|
-
@protocol = proto
|
82
|
-
headers << "Sec-WebSocket-Protocol: #{proto}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
(headers + ['','']).join("\r\n")
|
87
|
-
end
|
88
|
-
|
89
|
-
def create_handshake
|
90
|
-
Handshake.new(@socket.uri, @protocols)
|
91
|
-
end
|
92
|
-
|
93
|
-
def open?
|
94
|
-
true
|
95
|
-
end
|
96
|
-
|
97
|
-
def parse(data)
|
98
|
-
@reader.put(data.bytes.to_a)
|
99
|
-
buffer = true
|
100
|
-
while buffer
|
101
|
-
case @stage
|
102
|
-
when 0 then
|
103
|
-
buffer = @reader.read(1)
|
104
|
-
parse_opcode(buffer[0]) if buffer
|
105
|
-
|
106
|
-
when 1 then
|
107
|
-
buffer = @reader.read(1)
|
108
|
-
parse_length(buffer[0]) if buffer
|
109
|
-
|
110
|
-
when 2 then
|
111
|
-
buffer = @reader.read(@length_size)
|
112
|
-
parse_extended_length(buffer) if buffer
|
113
|
-
|
114
|
-
when 3 then
|
115
|
-
buffer = @reader.read(4)
|
116
|
-
if buffer
|
117
|
-
@mask = buffer
|
118
|
-
@stage = 4
|
119
|
-
end
|
120
|
-
|
121
|
-
when 4 then
|
122
|
-
buffer = @reader.read(@length)
|
123
|
-
if buffer
|
124
|
-
@payload = buffer
|
125
|
-
emit_frame
|
126
|
-
@stage = 0
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
nil
|
132
|
-
end
|
133
|
-
|
134
|
-
def frame(data, type = nil, code = nil)
|
135
|
-
return nil if @closed
|
136
|
-
|
137
|
-
is_text = (String === data)
|
138
|
-
opcode = OPCODES[type || (is_text ? :text : :binary)]
|
139
|
-
buffer = data.respond_to?(:bytes) ? data.bytes.to_a : data
|
140
|
-
insert = code ? 2 : 0
|
141
|
-
length = buffer.size + insert
|
142
|
-
header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10)
|
143
|
-
offset = header + (@masking ? 4 : 0)
|
144
|
-
masked = @masking ? MASK : 0
|
145
|
-
frame = Array.new(offset)
|
146
|
-
|
147
|
-
frame[0] = FIN | opcode
|
148
|
-
|
149
|
-
if length <= 125
|
150
|
-
frame[1] = masked | length
|
151
|
-
elsif length <= 65535
|
152
|
-
frame[1] = masked | 126
|
153
|
-
frame[2] = (length >> 8) & BYTE
|
154
|
-
frame[3] = length & BYTE
|
155
|
-
else
|
156
|
-
frame[1] = masked | 127
|
157
|
-
frame[2] = (length >> 56) & BYTE
|
158
|
-
frame[3] = (length >> 48) & BYTE
|
159
|
-
frame[4] = (length >> 40) & BYTE
|
160
|
-
frame[5] = (length >> 32) & BYTE
|
161
|
-
frame[6] = (length >> 24) & BYTE
|
162
|
-
frame[7] = (length >> 16) & BYTE
|
163
|
-
frame[8] = (length >> 8) & BYTE
|
164
|
-
frame[9] = length & BYTE
|
165
|
-
end
|
166
|
-
|
167
|
-
if code
|
168
|
-
buffer = [(code >> 8) & BYTE, code & BYTE] + buffer
|
169
|
-
end
|
170
|
-
|
171
|
-
if @masking
|
172
|
-
mask = [rand(256), rand(256), rand(256), rand(256)]
|
173
|
-
frame[header...offset] = mask
|
174
|
-
buffer = WebSocketMask.mask(buffer, mask)
|
175
|
-
end
|
176
|
-
|
177
|
-
frame.concat(buffer)
|
178
|
-
|
179
|
-
WebSocket.encode(frame)
|
180
|
-
end
|
181
|
-
|
182
|
-
def ping(message = '', &callback)
|
183
|
-
@ping_callbacks[message] = callback if callback
|
184
|
-
@socket.send(message, :ping)
|
185
|
-
end
|
186
|
-
|
187
|
-
def close(code = nil, reason = nil, &callback)
|
188
|
-
return if @closed
|
189
|
-
@closing_callback ||= callback
|
190
|
-
@socket.send(reason || '', :close, code || ERRORS[:normal_closure])
|
191
|
-
@closed = true
|
192
|
-
end
|
193
|
-
|
194
|
-
private
|
195
|
-
|
196
|
-
def parse_opcode(data)
|
197
|
-
if [RSV1, RSV2, RSV3].any? { |rsv| (data & rsv) == rsv }
|
198
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
199
|
-
end
|
200
|
-
|
201
|
-
@final = (data & FIN) == FIN
|
202
|
-
@opcode = (data & OPCODE)
|
203
|
-
@mask = []
|
204
|
-
@payload = []
|
205
|
-
|
206
|
-
unless OPCODES.values.include?(@opcode)
|
207
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
208
|
-
end
|
209
|
-
|
210
|
-
unless FRAGMENTED_OPCODES.include?(@opcode) or @final
|
211
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
212
|
-
end
|
213
|
-
|
214
|
-
if @mode and OPENING_OPCODES.include?(@opcode)
|
215
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
216
|
-
end
|
217
|
-
|
218
|
-
@stage = 1
|
219
|
-
end
|
220
|
-
|
221
|
-
def parse_length(data)
|
222
|
-
@masked = (data & MASK) == MASK
|
223
|
-
@length = (data & LENGTH)
|
224
|
-
|
225
|
-
if @length <= 125
|
226
|
-
@stage = @masked ? 3 : 4
|
227
|
-
else
|
228
|
-
@length_size = (@length == 126) ? 2 : 8
|
229
|
-
@stage = 2
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def parse_extended_length(buffer)
|
234
|
-
@length = integer(buffer)
|
235
|
-
@stage = @masked ? 3 : 4
|
236
|
-
end
|
237
|
-
|
238
|
-
def emit_frame
|
239
|
-
payload = @masked ? WebSocketMask.mask(@payload, @mask) : @payload
|
240
|
-
|
241
|
-
case @opcode
|
242
|
-
when OPCODES[:continuation] then
|
243
|
-
return @socket.close(ERRORS[:protocol_error], nil, false) unless @mode
|
244
|
-
@buffer.concat(payload)
|
245
|
-
if @final
|
246
|
-
message = @buffer
|
247
|
-
message = WebSocket.encode(message, true) if @mode == :text
|
248
|
-
reset
|
249
|
-
if message
|
250
|
-
@socket.receive(message)
|
251
|
-
else
|
252
|
-
@socket.close(ERRORS[:encoding_error], nil, false)
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
when OPCODES[:text] then
|
257
|
-
if @final
|
258
|
-
message = WebSocket.encode(payload, true)
|
259
|
-
if message
|
260
|
-
@socket.receive(message)
|
261
|
-
else
|
262
|
-
@socket.close(ERRORS[:encoding_error], nil, false)
|
263
|
-
end
|
264
|
-
else
|
265
|
-
@mode = :text
|
266
|
-
@buffer.concat(payload)
|
267
|
-
end
|
268
|
-
|
269
|
-
when OPCODES[:binary] then
|
270
|
-
if @final
|
271
|
-
@socket.receive(payload)
|
272
|
-
else
|
273
|
-
@mode = :binary
|
274
|
-
@buffer.concat(payload)
|
275
|
-
end
|
276
|
-
|
277
|
-
when OPCODES[:close] then
|
278
|
-
code = (payload.size >= 2) ? 256 * payload[0] + payload[1] : nil
|
279
|
-
|
280
|
-
unless (payload.size == 0) or
|
281
|
-
(code && code >= 3000 && code < 5000) or
|
282
|
-
ERROR_CODES.include?(code)
|
283
|
-
code = ERRORS[:protocol_error]
|
284
|
-
end
|
285
|
-
|
286
|
-
if payload.size > 125 or not WebSocket.valid_utf8?(payload[2..-1] || [])
|
287
|
-
code = ERRORS[:protocol_error]
|
288
|
-
end
|
289
|
-
|
290
|
-
reason = (payload.size > 2) ? WebSocket.encode(payload[2..-1], true) : nil
|
291
|
-
@socket.close(code, reason, false)
|
292
|
-
@closing_callback.call if @closing_callback
|
293
|
-
|
294
|
-
when OPCODES[:ping] then
|
295
|
-
return @socket.close(ERRORS[:protocol_error], nil, false) if payload.size > 125
|
296
|
-
@socket.send(payload, :pong)
|
297
|
-
|
298
|
-
when OPCODES[:pong] then
|
299
|
-
message = WebSocket.encode(payload, true)
|
300
|
-
callback = @ping_callbacks[message]
|
301
|
-
@ping_callbacks.delete(message)
|
302
|
-
callback.call if callback
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
def reset
|
307
|
-
@buffer = []
|
308
|
-
@mode = nil
|
309
|
-
end
|
310
|
-
|
311
|
-
def integer(bytes)
|
312
|
-
number = 0
|
313
|
-
bytes.each_with_index do |data, i|
|
314
|
-
number += data << (8 * (bytes.size - 1 - i))
|
315
|
-
end
|
316
|
-
number
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
end
|
321
|
-
end
|