faye 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye might be problematic. Click here for more details.
- data/History.txt +15 -3
- data/README.rdoc +2 -6
- data/lib/faye-browser-min.js +1 -1
- data/lib/faye.rb +25 -36
- data/lib/faye/adapters/rack_adapter.rb +43 -22
- data/lib/faye/engines/connection.rb +7 -10
- data/lib/faye/engines/memory.rb +28 -28
- data/lib/faye/engines/proxy.rb +109 -0
- data/lib/faye/mixins/logging.rb +1 -8
- data/lib/faye/mixins/timeouts.rb +1 -1
- data/lib/faye/protocol/channel.rb +3 -3
- data/lib/faye/protocol/client.rb +50 -45
- data/lib/faye/protocol/extensible.rb +11 -18
- data/lib/faye/protocol/server.rb +53 -38
- data/lib/faye/transport/http.rb +49 -27
- data/lib/faye/transport/transport.rb +3 -1
- data/lib/faye/transport/web_socket.rb +6 -10
- data/lib/faye/util/namespace.rb +2 -2
- data/spec/browser.html +3 -1
- data/spec/encoding_helper.rb +7 -0
- data/spec/javascript/client_spec.js +0 -5
- data/spec/javascript/engine/memory_spec.js +7 -0
- data/spec/javascript/engine_spec.js +22 -57
- data/spec/javascript/server/handshake_spec.js +10 -6
- data/spec/javascript/server/integration_spec.js +11 -10
- data/spec/javascript/server/publish_spec.js +85 -0
- data/spec/javascript/server_spec.js +5 -51
- data/spec/node.js +6 -6
- data/spec/ruby/client_spec.rb +1 -1
- data/spec/ruby/engine/memory_spec.rb +7 -0
- data/spec/ruby/{engine_spec.rb → engine_examples.rb} +28 -34
- data/spec/ruby/rack_adapter_spec.rb +1 -1
- data/spec/ruby/server/handshake_spec.rb +10 -6
- data/spec/ruby/server/publish_spec.rb +81 -0
- data/spec/ruby/server_spec.rb +6 -44
- data/spec/spec_helper.rb +5 -18
- data/spec/testswarm +1 -5
- metadata +105 -180
- data/lib/faye/engines/base.rb +0 -66
- data/lib/faye/engines/redis.rb +0 -225
- data/lib/faye/thin_extensions.rb +0 -75
- data/lib/faye/util/web_socket.rb +0 -89
- data/lib/faye/util/web_socket/api.rb +0 -103
- data/lib/faye/util/web_socket/client.rb +0 -82
- data/lib/faye/util/web_socket/draft75_parser.rb +0 -53
- data/lib/faye/util/web_socket/draft76_parser.rb +0 -53
- data/lib/faye/util/web_socket/protocol8_parser.rb +0 -324
- data/spec/javascript/web_socket/client_spec.js +0 -121
- data/spec/javascript/web_socket/draft75parser_spec.js +0 -39
- data/spec/javascript/web_socket/protocol8parser_spec.js +0 -153
- data/spec/redis.conf +0 -42
- data/spec/ruby/web_socket/client_spec.rb +0 -126
- data/spec/ruby/web_socket/draft75_parser_spec.rb +0 -41
- data/spec/ruby/web_socket/protocol8_parser_spec.rb +0 -145
@@ -1,103 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
CONNECTING = 0
|
5
|
-
OPEN = 1
|
6
|
-
CLOSING = 2
|
7
|
-
CLOSED = 3
|
8
|
-
|
9
|
-
module API
|
10
|
-
attr_reader :url, :ready_state, :buffered_amount
|
11
|
-
attr_accessor :onopen, :onmessage, :onerror, :onclose
|
12
|
-
|
13
|
-
include Publisher
|
14
|
-
|
15
|
-
def receive(data)
|
16
|
-
return false unless ready_state == OPEN
|
17
|
-
event = Event.new('message')
|
18
|
-
event.init_event('message', false, false)
|
19
|
-
event.data = data
|
20
|
-
dispatch_event(event)
|
21
|
-
end
|
22
|
-
|
23
|
-
def send(data, type = nil, error_type = nil)
|
24
|
-
return false if ready_state == CLOSED
|
25
|
-
data = Faye.encode(data) if String === data
|
26
|
-
frame = @parser.frame(data, type, error_type)
|
27
|
-
@stream.write(frame) if frame
|
28
|
-
end
|
29
|
-
|
30
|
-
def close(code = nil, reason = nil, ack = true)
|
31
|
-
return if [CLOSING, CLOSED].include?(ready_state)
|
32
|
-
|
33
|
-
@ready_state = CLOSING
|
34
|
-
|
35
|
-
close = lambda do
|
36
|
-
@ready_state = CLOSED
|
37
|
-
@stream.close_connection_after_writing
|
38
|
-
event = Event.new('close', :code => code || 1000, :reason => reason || '')
|
39
|
-
event.init_event('close', false, false)
|
40
|
-
dispatch_event(event)
|
41
|
-
end
|
42
|
-
|
43
|
-
if ack
|
44
|
-
if @parser.respond_to?(:close)
|
45
|
-
@parser.close(code, reason, &close)
|
46
|
-
else
|
47
|
-
close.call
|
48
|
-
end
|
49
|
-
else
|
50
|
-
@parser.close(code, reason) if @parser.respond_to?(:close)
|
51
|
-
close.call
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def add_event_listener(type, listener, use_capture)
|
56
|
-
bind(type, listener)
|
57
|
-
end
|
58
|
-
|
59
|
-
def remove_event_listener(type, listener, use_capture)
|
60
|
-
unbind(type, listener)
|
61
|
-
end
|
62
|
-
|
63
|
-
def dispatch_event(event)
|
64
|
-
event.target = event.current_target = self
|
65
|
-
event.event_phase = Event::AT_TARGET
|
66
|
-
|
67
|
-
trigger(event.type, event)
|
68
|
-
callback = __send__("on#{ event.type }")
|
69
|
-
callback.call(event) if callback
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class Event
|
74
|
-
attr_reader :type, :bubbles, :cancelable
|
75
|
-
attr_accessor :target, :current_target, :event_phase, :data
|
76
|
-
|
77
|
-
CAPTURING_PHASE = 1
|
78
|
-
AT_TARGET = 2
|
79
|
-
BUBBLING_PHASE = 3
|
80
|
-
|
81
|
-
def initialize(event_type, options = {})
|
82
|
-
@type = event_type
|
83
|
-
metaclass = (class << self ; self ; end)
|
84
|
-
options.each do |key, value|
|
85
|
-
metaclass.__send__(:define_method, key) { value }
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def init_event(event_type, can_bubble, cancelable)
|
90
|
-
@type = event_type
|
91
|
-
@bubbles = can_bubble
|
92
|
-
@cancelable = cancelable
|
93
|
-
end
|
94
|
-
|
95
|
-
def stop_propagation
|
96
|
-
end
|
97
|
-
|
98
|
-
def prevent_default
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
103
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class Client
|
5
|
-
include API
|
6
|
-
attr_reader :uri
|
7
|
-
|
8
|
-
def initialize(url)
|
9
|
-
@parser = Protocol8Parser.new(self, :masking => true)
|
10
|
-
@url = url
|
11
|
-
@uri = URI.parse(url)
|
12
|
-
|
13
|
-
@ready_state = CONNECTING
|
14
|
-
@buffered_amount = 0
|
15
|
-
|
16
|
-
port = @uri.port || (@uri.scheme == 'wss' ? 443 : 80)
|
17
|
-
|
18
|
-
EventMachine.connect(@uri.host, port, Connection) do |conn|
|
19
|
-
@stream = conn
|
20
|
-
conn.parent = self
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def on_connect
|
27
|
-
@stream.start_tls if @uri.scheme == 'wss'
|
28
|
-
@handshake = @parser.create_handshake
|
29
|
-
@message = []
|
30
|
-
@stream.write(@handshake.request_data)
|
31
|
-
end
|
32
|
-
|
33
|
-
def receive_data(data)
|
34
|
-
data = Faye.encode(data)
|
35
|
-
|
36
|
-
case @ready_state
|
37
|
-
when CONNECTING then
|
38
|
-
@message += @handshake.parse(data)
|
39
|
-
return unless @handshake.complete?
|
40
|
-
|
41
|
-
if @handshake.valid?
|
42
|
-
@ready_state = OPEN
|
43
|
-
event = Event.new('open')
|
44
|
-
event.init_event('open', false, false)
|
45
|
-
dispatch_event(event)
|
46
|
-
|
47
|
-
receive_data(@message)
|
48
|
-
else
|
49
|
-
@ready_state = CLOSED
|
50
|
-
event = Event.new('error')
|
51
|
-
event.init_event('error', false, false)
|
52
|
-
dispatch_event(event)
|
53
|
-
end
|
54
|
-
|
55
|
-
when OPEN, CLOSING then
|
56
|
-
@parser.parse(data)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
module Connection
|
61
|
-
attr_accessor :parent
|
62
|
-
|
63
|
-
def connection_completed
|
64
|
-
parent.__send__(:on_connect)
|
65
|
-
end
|
66
|
-
|
67
|
-
def receive_data(data)
|
68
|
-
parent.__send__(:receive_data, data)
|
69
|
-
end
|
70
|
-
|
71
|
-
def unbind
|
72
|
-
parent.close(1006, '', false)
|
73
|
-
end
|
74
|
-
|
75
|
-
def write(data)
|
76
|
-
send_data(data)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class Draft75Parser
|
5
|
-
def initialize(web_socket)
|
6
|
-
@socket = web_socket
|
7
|
-
@buffer = []
|
8
|
-
@buffering = false
|
9
|
-
end
|
10
|
-
|
11
|
-
def version
|
12
|
-
'draft-75'
|
13
|
-
end
|
14
|
-
|
15
|
-
def handshake_response
|
16
|
-
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
17
|
-
upgrade << "Upgrade: WebSocket\r\n"
|
18
|
-
upgrade << "Connection: Upgrade\r\n"
|
19
|
-
upgrade << "WebSocket-Origin: #{@socket.env['HTTP_ORIGIN']}\r\n"
|
20
|
-
upgrade << "WebSocket-Location: #{@socket.url}\r\n"
|
21
|
-
upgrade << "\r\n"
|
22
|
-
upgrade
|
23
|
-
end
|
24
|
-
|
25
|
-
def parse(data)
|
26
|
-
data.each_byte(&method(:handle_byte))
|
27
|
-
end
|
28
|
-
|
29
|
-
def frame(data, type = nil, error_type = nil)
|
30
|
-
["\x00", data, "\xFF"].map(&Faye.method(:encode)) * ''
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def handle_byte(data)
|
36
|
-
case data
|
37
|
-
when 0x00 then
|
38
|
-
@buffering = true
|
39
|
-
|
40
|
-
when 0xFF then
|
41
|
-
@socket.receive(Faye.encode(@buffer))
|
42
|
-
@buffer = []
|
43
|
-
@buffering = false
|
44
|
-
|
45
|
-
else
|
46
|
-
@buffer.push(data) if @buffering
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class Draft76Parser < Draft75Parser
|
5
|
-
def version
|
6
|
-
'draft-76'
|
7
|
-
end
|
8
|
-
|
9
|
-
def handshake_response
|
10
|
-
env = @socket.env
|
11
|
-
|
12
|
-
key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
|
13
|
-
value1 = number_from_key(key1) / spaces_in_key(key1)
|
14
|
-
|
15
|
-
key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
|
16
|
-
value2 = number_from_key(key2) / spaces_in_key(key2)
|
17
|
-
|
18
|
-
hash = Digest::MD5.digest(big_endian(value1) +
|
19
|
-
big_endian(value2) +
|
20
|
-
env['rack.input'].read)
|
21
|
-
|
22
|
-
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
23
|
-
upgrade << "Upgrade: WebSocket\r\n"
|
24
|
-
upgrade << "Connection: Upgrade\r\n"
|
25
|
-
upgrade << "Sec-WebSocket-Origin: #{env['HTTP_ORIGIN']}\r\n"
|
26
|
-
upgrade << "Sec-WebSocket-Location: #{@socket.url}\r\n"
|
27
|
-
upgrade << "\r\n"
|
28
|
-
upgrade << hash
|
29
|
-
upgrade
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def number_from_key(key)
|
35
|
-
key.scan(/[0-9]/).join('').to_i(10)
|
36
|
-
end
|
37
|
-
|
38
|
-
def spaces_in_key(key)
|
39
|
-
key.scan(/ /).size
|
40
|
-
end
|
41
|
-
|
42
|
-
def big_endian(number)
|
43
|
-
string = ''
|
44
|
-
[24,16,8,0].each do |offset|
|
45
|
-
string << (number >> offset & 0xFF).chr
|
46
|
-
end
|
47
|
-
string
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
@@ -1,324 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class WebSocket
|
3
|
-
|
4
|
-
class Protocol8Parser
|
5
|
-
GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
|
6
|
-
|
7
|
-
FIN = MASK = 0b10000000
|
8
|
-
RSV1 = 0b01000000
|
9
|
-
RSV2 = 0b00100000
|
10
|
-
RSV3 = 0b00010000
|
11
|
-
OPCODE = 0b00001111
|
12
|
-
LENGTH = 0b01111111
|
13
|
-
|
14
|
-
OPCODES = {
|
15
|
-
:continuation => 0,
|
16
|
-
:text => 1,
|
17
|
-
:binary => 2,
|
18
|
-
:close => 8,
|
19
|
-
:ping => 9,
|
20
|
-
:pong => 10
|
21
|
-
}
|
22
|
-
|
23
|
-
FRAGMENTED_OPCODES = OPCODES.values_at(:continuation, :text, :binary)
|
24
|
-
OPENING_OPCODES = OPCODES.values_at(:text, :binary)
|
25
|
-
|
26
|
-
ERRORS = {
|
27
|
-
:normal_closure => 1000,
|
28
|
-
:going_away => 1001,
|
29
|
-
:protocol_error => 1002,
|
30
|
-
:unacceptable => 1003,
|
31
|
-
:encoding_error => 1007,
|
32
|
-
:policy_violation => 1008,
|
33
|
-
:too_large => 1009,
|
34
|
-
:extension_error => 1010
|
35
|
-
}
|
36
|
-
|
37
|
-
ERROR_CODES = ERRORS.values
|
38
|
-
|
39
|
-
class Handshake
|
40
|
-
def initialize(uri)
|
41
|
-
@uri = uri
|
42
|
-
@key = Base64.encode64((1..16).map { rand(255).chr } * '').strip
|
43
|
-
@accept = Base64.encode64(Digest::SHA1.digest(@key + GUID)).strip
|
44
|
-
@buffer = []
|
45
|
-
end
|
46
|
-
|
47
|
-
def request_data
|
48
|
-
hostname = @uri.host + (@uri.port ? ":#{@uri.port}" : '')
|
49
|
-
|
50
|
-
handshake = "GET #{@uri.path}#{@uri.query ? '?' : ''}#{@uri.query} HTTP/1.1\r\n"
|
51
|
-
handshake << "Host: #{hostname}\r\n"
|
52
|
-
handshake << "Upgrade: websocket\r\n"
|
53
|
-
handshake << "Connection: Upgrade\r\n"
|
54
|
-
handshake << "Sec-WebSocket-Key: #{@key}\r\n"
|
55
|
-
handshake << "Sec-WebSocket-Version: 8\r\n"
|
56
|
-
handshake << "\r\n"
|
57
|
-
|
58
|
-
handshake
|
59
|
-
end
|
60
|
-
|
61
|
-
def parse(data)
|
62
|
-
message = []
|
63
|
-
complete = false
|
64
|
-
data.each_byte do |byte|
|
65
|
-
if complete
|
66
|
-
message << byte
|
67
|
-
else
|
68
|
-
@buffer << byte
|
69
|
-
complete ||= complete?
|
70
|
-
end
|
71
|
-
end
|
72
|
-
message
|
73
|
-
end
|
74
|
-
|
75
|
-
def complete?
|
76
|
-
@buffer[-4..-1] == [0x0D, 0x0A, 0x0D, 0x0A]
|
77
|
-
end
|
78
|
-
|
79
|
-
def valid?
|
80
|
-
data = Faye.encode(@buffer)
|
81
|
-
response = Net::HTTPResponse.read_new(Net::BufferedIO.new(StringIO.new(data)))
|
82
|
-
return false unless response.code.to_i == 101
|
83
|
-
|
84
|
-
upgrade, connection = response['Upgrade'], response['Connection']
|
85
|
-
|
86
|
-
upgrade and upgrade =~ /^websocket$/i and
|
87
|
-
connection and connection.split(/\s*,\s*/).include?('Upgrade') and
|
88
|
-
response['Sec-WebSocket-Accept'] == @accept
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def initialize(web_socket, options = {})
|
93
|
-
reset
|
94
|
-
@socket = web_socket
|
95
|
-
@stage = 0
|
96
|
-
@masking = options[:masking]
|
97
|
-
end
|
98
|
-
|
99
|
-
def version
|
100
|
-
'protocol-8'
|
101
|
-
end
|
102
|
-
|
103
|
-
def handshake_response
|
104
|
-
sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
|
105
|
-
return '' unless String === sec_key
|
106
|
-
|
107
|
-
accept = Base64.encode64(Digest::SHA1.digest(sec_key + GUID)).strip
|
108
|
-
|
109
|
-
upgrade = "HTTP/1.1 101 Switching Protocols\r\n"
|
110
|
-
upgrade << "Upgrade: websocket\r\n"
|
111
|
-
upgrade << "Connection: Upgrade\r\n"
|
112
|
-
upgrade << "Sec-WebSocket-Accept: #{accept}\r\n"
|
113
|
-
upgrade << "\r\n"
|
114
|
-
upgrade
|
115
|
-
end
|
116
|
-
|
117
|
-
def create_handshake
|
118
|
-
Handshake.new(@socket.uri)
|
119
|
-
end
|
120
|
-
|
121
|
-
def parse(data)
|
122
|
-
data.each_byte do |byte|
|
123
|
-
case @stage
|
124
|
-
when 0 then parse_opcode(byte)
|
125
|
-
when 1 then parse_length(byte)
|
126
|
-
when 2 then parse_extended_length(byte)
|
127
|
-
when 3 then parse_mask(byte)
|
128
|
-
when 4 then parse_payload(byte)
|
129
|
-
end
|
130
|
-
emit_frame if @stage == 4 and @length == 0
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def frame(data, type = nil, code = nil)
|
135
|
-
return nil if @closed
|
136
|
-
|
137
|
-
type ||= (String === data ? :text : :binary)
|
138
|
-
data = data.bytes.to_a if data.respond_to?(:bytes)
|
139
|
-
|
140
|
-
if code
|
141
|
-
data = [code].pack('n').bytes.to_a + data
|
142
|
-
end
|
143
|
-
|
144
|
-
frame = (FIN | OPCODES[type]).chr
|
145
|
-
length = data.size
|
146
|
-
masked = @masking ? MASK : 0
|
147
|
-
|
148
|
-
case length
|
149
|
-
when 0..125 then
|
150
|
-
frame << (masked | length).chr
|
151
|
-
when 126..65535 then
|
152
|
-
frame << (masked | 126).chr
|
153
|
-
frame << [length].pack('n')
|
154
|
-
else
|
155
|
-
frame << (masked | 127).chr
|
156
|
-
frame << [length >> 32, length & 0xFFFFFFFF].pack('NN')
|
157
|
-
end
|
158
|
-
|
159
|
-
if @masking
|
160
|
-
mask = (1..4).map { rand 256 }
|
161
|
-
data.each_with_index do |byte, i|
|
162
|
-
data[i] = byte ^ mask[i % 4]
|
163
|
-
end
|
164
|
-
frame << mask.pack('C*')
|
165
|
-
end
|
166
|
-
|
167
|
-
Faye.encode(frame) + Faye.encode(data)
|
168
|
-
end
|
169
|
-
|
170
|
-
def close(code = nil, reason = nil, &callback)
|
171
|
-
return if @closed
|
172
|
-
@closing_callback ||= callback
|
173
|
-
@socket.send(reason || '', :close, code || ERRORS[:normal_closure])
|
174
|
-
@closed = true
|
175
|
-
end
|
176
|
-
|
177
|
-
private
|
178
|
-
|
179
|
-
def parse_opcode(data)
|
180
|
-
if [RSV1, RSV2, RSV3].any? { |rsv| (data & rsv) == rsv }
|
181
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
182
|
-
end
|
183
|
-
|
184
|
-
@final = (data & FIN) == FIN
|
185
|
-
@opcode = (data & OPCODE)
|
186
|
-
@mask = []
|
187
|
-
@payload = []
|
188
|
-
|
189
|
-
unless OPCODES.values.include?(@opcode)
|
190
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
191
|
-
end
|
192
|
-
|
193
|
-
unless FRAGMENTED_OPCODES.include?(@opcode) or @final
|
194
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
195
|
-
end
|
196
|
-
|
197
|
-
if @mode and OPENING_OPCODES.include?(@opcode)
|
198
|
-
return @socket.close(ERRORS[:protocol_error], nil, false)
|
199
|
-
end
|
200
|
-
|
201
|
-
@stage = 1
|
202
|
-
end
|
203
|
-
|
204
|
-
def parse_length(data)
|
205
|
-
@masked = (data & MASK) == MASK
|
206
|
-
@length = (data & LENGTH)
|
207
|
-
|
208
|
-
if @length <= 125
|
209
|
-
@stage = @masked ? 3 : 4
|
210
|
-
else
|
211
|
-
@length_buffer = []
|
212
|
-
@length_size = (@length == 126) ? 2 : 8
|
213
|
-
@stage = 2
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def parse_extended_length(data)
|
218
|
-
@length_buffer << data
|
219
|
-
return unless @length_buffer.size == @length_size
|
220
|
-
@length = integer(@length_buffer)
|
221
|
-
@stage = @masked ? 3 : 4
|
222
|
-
end
|
223
|
-
|
224
|
-
def parse_mask(data)
|
225
|
-
@mask << data
|
226
|
-
return if @mask.size < 4
|
227
|
-
@stage = 4
|
228
|
-
end
|
229
|
-
|
230
|
-
def parse_payload(data)
|
231
|
-
@payload << data
|
232
|
-
return if @payload.size < @length
|
233
|
-
emit_frame
|
234
|
-
end
|
235
|
-
|
236
|
-
def emit_frame
|
237
|
-
payload = unmask(@payload, @mask)
|
238
|
-
|
239
|
-
case @opcode
|
240
|
-
when OPCODES[:continuation] then
|
241
|
-
return @socket.close(ERRORS[:protocol_error], nil, false) unless @mode
|
242
|
-
@buffer += payload
|
243
|
-
if @final
|
244
|
-
message = @buffer
|
245
|
-
message = Faye.encode(message, true) if @mode == :text
|
246
|
-
reset
|
247
|
-
if message
|
248
|
-
@socket.receive(message)
|
249
|
-
else
|
250
|
-
@socket.close(ERRORS[:encoding_error], nil, false)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
when OPCODES[:text] then
|
255
|
-
if @final
|
256
|
-
message = Faye.encode(payload, true)
|
257
|
-
if message
|
258
|
-
@socket.receive(message)
|
259
|
-
else
|
260
|
-
@socket.close(ERRORS[:encoding_error], nil, false)
|
261
|
-
end
|
262
|
-
else
|
263
|
-
@mode = :text
|
264
|
-
@buffer += payload
|
265
|
-
end
|
266
|
-
|
267
|
-
when OPCODES[:binary] then
|
268
|
-
if @final
|
269
|
-
@socket.receive(payload)
|
270
|
-
else
|
271
|
-
@mode = :binary
|
272
|
-
@buffer += payload
|
273
|
-
end
|
274
|
-
|
275
|
-
when OPCODES[:close] then
|
276
|
-
code = (payload.size >= 2) ? 256 * payload[0] + payload[1] : nil
|
277
|
-
|
278
|
-
unless (payload.size == 0) or
|
279
|
-
(code && code >= 3000 && code < 5000) or
|
280
|
-
ERROR_CODES.include?(code)
|
281
|
-
code = ERRORS[:protocol_error]
|
282
|
-
end
|
283
|
-
|
284
|
-
if payload.size > 125 or not Faye.valid_utf8?(payload[2..-1] || [])
|
285
|
-
code = ERRORS[:protocol_error]
|
286
|
-
end
|
287
|
-
|
288
|
-
reason = (payload.size > 2) ? Faye.encode(payload[2..-1], true) : nil
|
289
|
-
@socket.close(code, reason, false)
|
290
|
-
@closing_callback.call if @closing_callback
|
291
|
-
|
292
|
-
when OPCODES[:ping] then
|
293
|
-
return @socket.close(ERRORS[:protocol_error], nil, false) if payload.size > 125
|
294
|
-
@socket.send(payload, :pong)
|
295
|
-
end
|
296
|
-
@stage = 0
|
297
|
-
end
|
298
|
-
|
299
|
-
def reset
|
300
|
-
@buffer = []
|
301
|
-
@mode = nil
|
302
|
-
end
|
303
|
-
|
304
|
-
def integer(bytes)
|
305
|
-
number = 0
|
306
|
-
bytes.each_with_index do |data, i|
|
307
|
-
number += data << (8 * (bytes.size - 1 - i))
|
308
|
-
end
|
309
|
-
number
|
310
|
-
end
|
311
|
-
|
312
|
-
def unmask(payload, mask)
|
313
|
-
unmasked = []
|
314
|
-
payload.each_with_index do |byte, i|
|
315
|
-
byte = byte ^ mask[i % 4] if mask.size > 0
|
316
|
-
unmasked << byte
|
317
|
-
end
|
318
|
-
unmasked
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|