faye-websocket 0.4.6 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye-websocket might be problematic. Click here for more details.
- data/CHANGELOG.txt +7 -0
- data/README.rdoc +24 -24
- data/examples/app.rb +10 -10
- data/examples/autobahn_client.rb +16 -11
- data/examples/client.rb +4 -4
- data/examples/config.ru +3 -3
- data/examples/sse.html +8 -8
- data/examples/ws.html +8 -8
- data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +7 -7
- data/ext/faye_websocket_mask/faye_websocket_mask.c +2 -2
- data/lib/faye/adapters/goliath.rb +5 -5
- data/lib/faye/adapters/rainbows.rb +3 -3
- data/lib/faye/adapters/rainbows_client.rb +12 -12
- data/lib/faye/adapters/thin.rb +10 -9
- data/lib/faye/eventsource.rb +26 -26
- data/lib/faye/websocket.rb +40 -40
- data/lib/faye/websocket/adapter.rb +5 -5
- data/lib/faye/websocket/api.rb +28 -25
- data/lib/faye/websocket/api/event.rb +7 -7
- data/lib/faye/websocket/api/event_target.rb +8 -8
- data/lib/faye/websocket/client.rb +18 -18
- data/lib/faye/websocket/draft75_parser.rb +13 -13
- data/lib/faye/websocket/draft76_parser.rb +17 -17
- data/lib/faye/websocket/hybi_parser.rb +4 -4
- data/lib/faye/websocket/utf8_match.rb +2 -2
- data/spec/faye/websocket/client_spec.rb +32 -49
- data/spec/faye/websocket/draft75_parser_examples.rb +7 -7
- data/spec/faye/websocket/draft75_parser_spec.rb +4 -4
- data/spec/faye/websocket/draft76_parser_spec.rb +5 -5
- data/spec/spec_helper.rb +4 -4
- metadata +22 -6
@@ -1,21 +1,21 @@
|
|
1
1
|
module Faye
|
2
2
|
class WebSocket
|
3
|
-
|
3
|
+
|
4
4
|
module Adapter
|
5
5
|
def websocket?
|
6
6
|
e = defined?(@env) ? @env : env
|
7
7
|
WebSocket.websocket?(e)
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def eventsource?
|
11
11
|
e = defined?(@env) ? @env : env
|
12
12
|
EventSource.eventsource?(e)
|
13
13
|
end
|
14
|
-
|
15
|
-
def
|
14
|
+
|
15
|
+
def socket_connection?
|
16
16
|
websocket? or eventsource?
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
end
|
21
21
|
end
|
data/lib/faye/websocket/api.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Faye
|
2
2
|
class WebSocket
|
3
|
-
|
3
|
+
|
4
4
|
module API
|
5
5
|
module ReadyStates
|
6
6
|
CONNECTING = 0
|
@@ -8,35 +8,35 @@ module Faye
|
|
8
8
|
CLOSING = 2
|
9
9
|
CLOSED = 3
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
class IllegalStateError < StandardError
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
require File.expand_path('../api/event_target', __FILE__)
|
16
16
|
require File.expand_path('../api/event', __FILE__)
|
17
17
|
include EventTarget
|
18
18
|
include ReadyStates
|
19
|
-
|
19
|
+
|
20
20
|
attr_reader :url, :ready_state, :buffered_amount
|
21
|
-
|
21
|
+
|
22
22
|
private
|
23
|
-
|
23
|
+
|
24
24
|
def open
|
25
25
|
return if @parser and not @parser.open?
|
26
26
|
@ready_state = OPEN
|
27
|
-
|
27
|
+
|
28
28
|
buffer = @send_buffer || []
|
29
29
|
while message = buffer.shift
|
30
30
|
send(*message)
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
event = Event.new('open')
|
34
34
|
event.init_event('open', false, false)
|
35
35
|
dispatch_event(event)
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
public
|
39
|
-
|
39
|
+
|
40
40
|
def receive(data)
|
41
41
|
return false unless @ready_state == OPEN
|
42
42
|
event = Event.new('message')
|
@@ -44,7 +44,7 @@ module Faye
|
|
44
44
|
event.data = data
|
45
45
|
dispatch_event(event)
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def send(data, type = nil, error_type = nil)
|
49
49
|
if @ready_state == CONNECTING
|
50
50
|
if @send_buffer
|
@@ -54,22 +54,21 @@ module Faye
|
|
54
54
|
raise IllegalStateError, 'Cannot call send(), socket is not open yet'
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
return false if @ready_state == CLOSED
|
59
|
-
|
59
|
+
|
60
60
|
data = data.to_s unless Array === data
|
61
|
-
|
61
|
+
|
62
62
|
data = WebSocket.encode(data) if String === data
|
63
63
|
frame = @parser.frame(data, type, error_type)
|
64
64
|
@stream.write(frame) if frame
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def close(code = nil, reason = nil, ack = true)
|
68
|
-
return if
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
close = lambda do
|
68
|
+
return if @ready_state == CLOSED
|
69
|
+
return if @ready_state == CLOSING && ack
|
70
|
+
|
71
|
+
finalize = lambda do
|
73
72
|
@ready_state = CLOSED
|
74
73
|
EventMachine.cancel_timer(@ping_timer) if @ping_timer
|
75
74
|
@stream.close_connection_after_writing
|
@@ -77,20 +76,24 @@ module Faye
|
|
77
76
|
event.init_event('close', false, false)
|
78
77
|
dispatch_event(event)
|
79
78
|
end
|
80
|
-
|
79
|
+
|
80
|
+
return finalize.call if @ready_state == CONNECTING
|
81
|
+
|
82
|
+
@ready_state = CLOSING
|
83
|
+
|
81
84
|
if ack
|
82
85
|
if @parser.respond_to?(:close)
|
83
|
-
@parser.close(code, reason, &
|
86
|
+
@parser.close(code, reason, &finalize)
|
84
87
|
else
|
85
|
-
|
88
|
+
finalize.call
|
86
89
|
end
|
87
90
|
else
|
88
91
|
@parser.close(code, reason) if @parser.respond_to?(:close)
|
89
|
-
|
92
|
+
finalize.call
|
90
93
|
end
|
91
94
|
end
|
92
95
|
end
|
93
|
-
|
96
|
+
|
94
97
|
end
|
95
98
|
end
|
96
99
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Faye::WebSocket::API
|
2
2
|
class Event
|
3
|
-
|
3
|
+
|
4
4
|
attr_reader :type, :bubbles, :cancelable
|
5
5
|
attr_accessor :target, :current_target, :event_phase, :data
|
6
|
-
|
6
|
+
|
7
7
|
CAPTURING_PHASE = 1
|
8
8
|
AT_TARGET = 2
|
9
9
|
BUBBLING_PHASE = 3
|
10
|
-
|
10
|
+
|
11
11
|
def initialize(event_type, options = {})
|
12
12
|
@type = event_type
|
13
13
|
metaclass = (class << self ; self ; end)
|
@@ -15,19 +15,19 @@ module Faye::WebSocket::API
|
|
15
15
|
metaclass.__send__(:define_method, key) { value }
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def init_event(event_type, can_bubble, cancelable)
|
20
20
|
@type = event_type
|
21
21
|
@bubbles = can_bubble
|
22
22
|
@cancelable = cancelable
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def stop_propagation
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def prevent_default
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -1,34 +1,34 @@
|
|
1
1
|
module Faye::WebSocket::API
|
2
2
|
module EventTarget
|
3
|
-
|
3
|
+
|
4
4
|
attr_accessor :onopen, :onmessage, :onerror, :onclose
|
5
|
-
|
5
|
+
|
6
6
|
def add_event_listener(event_type, listener, use_capture = false)
|
7
7
|
@listeners ||= {}
|
8
8
|
list = @listeners[event_type] ||= []
|
9
9
|
list << listener
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def remove_event_listener(event_type, listener, use_capture = false)
|
13
13
|
return unless @listeners and @listeners[event_type]
|
14
14
|
return @listeners.delete(event_type) unless listener
|
15
|
-
|
15
|
+
|
16
16
|
@listeners[event_type].delete_if(&listener.method(:==))
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def dispatch_event(event)
|
20
20
|
event.target = event.current_target = self
|
21
21
|
event.event_phase = Event::AT_TARGET
|
22
|
-
|
22
|
+
|
23
23
|
callback = __send__("on#{ event.type }")
|
24
24
|
callback.call(event) if callback
|
25
|
-
|
25
|
+
|
26
26
|
return unless @listeners and @listeners[event.type]
|
27
27
|
@listeners[event.type].each do |listener|
|
28
28
|
listener.call(event)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -1,51 +1,51 @@
|
|
1
1
|
module Faye
|
2
2
|
class WebSocket
|
3
|
-
|
3
|
+
|
4
4
|
class Client
|
5
5
|
include API
|
6
6
|
attr_reader :protocol, :uri
|
7
|
-
|
7
|
+
|
8
8
|
def initialize(url, protocols = nil)
|
9
9
|
@parser = HybiParser.new(self, :masking => true, :protocols => protocols)
|
10
10
|
@url = url
|
11
11
|
@uri = URI.parse(url)
|
12
|
-
|
12
|
+
|
13
13
|
@protocol = ''
|
14
14
|
@ready_state = CONNECTING
|
15
15
|
@buffered_amount = 0
|
16
|
-
|
16
|
+
|
17
17
|
port = @uri.port || (@uri.scheme == 'wss' ? 443 : 80)
|
18
|
-
|
18
|
+
|
19
19
|
EventMachine.connect(@uri.host, port, Connection) do |conn|
|
20
20
|
@stream = conn
|
21
21
|
conn.parent = self
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
private
|
26
|
-
|
26
|
+
|
27
27
|
def on_connect
|
28
28
|
@stream.start_tls if @uri.scheme == 'wss'
|
29
29
|
@handshake = @parser.create_handshake
|
30
30
|
@message = []
|
31
31
|
@stream.write(@handshake.request_data)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def receive_data(data)
|
35
35
|
data = WebSocket.encode(data)
|
36
|
-
|
36
|
+
|
37
37
|
case @ready_state
|
38
38
|
when CONNECTING then
|
39
39
|
@message += @handshake.parse(data)
|
40
40
|
return unless @handshake.complete?
|
41
|
-
|
41
|
+
|
42
42
|
if @handshake.valid?
|
43
43
|
@protocol = @handshake.protocol || ''
|
44
44
|
@ready_state = OPEN
|
45
45
|
event = Event.new('open')
|
46
46
|
event.init_event('open', false, false)
|
47
47
|
dispatch_event(event)
|
48
|
-
|
48
|
+
|
49
49
|
receive_data(@message)
|
50
50
|
else
|
51
51
|
@ready_state = CLOSED
|
@@ -53,32 +53,32 @@ module Faye
|
|
53
53
|
event.init_event('close', false, false)
|
54
54
|
dispatch_event(event)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
when OPEN, CLOSING then
|
58
58
|
@parser.parse(data)
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
module Connection
|
63
63
|
attr_accessor :parent
|
64
|
-
|
64
|
+
|
65
65
|
def connection_completed
|
66
66
|
parent.__send__(:on_connect)
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def receive_data(data)
|
70
70
|
parent.__send__(:receive_data, data)
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def unbind
|
74
74
|
parent.close(1006, '', false)
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
def write(data)
|
78
78
|
send_data(data) rescue nil
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
end
|
84
84
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
module Faye
|
2
2
|
class WebSocket
|
3
|
-
|
3
|
+
|
4
4
|
class Draft75Parser
|
5
5
|
attr_reader :protocol
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(web_socket, options = {})
|
8
8
|
@socket = web_socket
|
9
9
|
@stage = 0
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def version
|
13
13
|
'hixie-75'
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def handshake_response
|
17
17
|
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
18
18
|
upgrade << "Upgrade: WebSocket\r\n"
|
@@ -22,21 +22,21 @@ module Faye
|
|
22
22
|
upgrade << "\r\n"
|
23
23
|
upgrade
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def open?
|
27
27
|
true
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def parse(buffer)
|
31
31
|
buffer.each_byte do |data|
|
32
32
|
case @stage
|
33
33
|
when 0 then
|
34
34
|
parse_leading_byte(data)
|
35
|
-
|
35
|
+
|
36
36
|
when 1 then
|
37
37
|
value = (data & 0x7F)
|
38
38
|
@length = value + 128 * @length
|
39
|
-
|
39
|
+
|
40
40
|
if @closing and @length.zero?
|
41
41
|
@socket.close(nil, nil, false)
|
42
42
|
elsif (0x80 & data) != 0x80
|
@@ -48,7 +48,7 @@ module Faye
|
|
48
48
|
@stage = 2
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
when 2 then
|
53
53
|
if data == 0xFF
|
54
54
|
@socket.receive(WebSocket.encode(@buffer))
|
@@ -61,10 +61,10 @@ module Faye
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
nil
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def parse_leading_byte(data)
|
69
69
|
if (0x80 & data) == 0x80
|
70
70
|
@length = 0
|
@@ -75,13 +75,13 @@ module Faye
|
|
75
75
|
@stage = 2
|
76
76
|
end
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def frame(data, type = nil, error_type = nil)
|
80
80
|
return WebSocket.encode(data) if Array === data
|
81
81
|
["\x00", data, "\xFF"].map(&WebSocket.method(:encode)) * ''
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module Faye
|
2
2
|
class WebSocket
|
3
|
-
|
3
|
+
|
4
4
|
class Draft76Parser < Draft75Parser
|
5
5
|
def version
|
6
6
|
'hixie-76'
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def handshake_response
|
10
10
|
env = @socket.env
|
11
11
|
signature = handshake_signature(env['rack.input'].read)
|
12
|
-
|
12
|
+
|
13
13
|
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
14
14
|
upgrade << "Upgrade: WebSocket\r\n"
|
15
15
|
upgrade << "Connection: Upgrade\r\n"
|
@@ -19,57 +19,57 @@ module Faye
|
|
19
19
|
upgrade << signature if signature
|
20
20
|
upgrade
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def handshake_signature(head)
|
24
24
|
return nil if head.empty?
|
25
25
|
env = @socket.env
|
26
|
-
|
26
|
+
|
27
27
|
key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
|
28
28
|
value1 = number_from_key(key1) / spaces_in_key(key1)
|
29
|
-
|
29
|
+
|
30
30
|
key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
|
31
31
|
value2 = number_from_key(key2) / spaces_in_key(key2)
|
32
|
-
|
32
|
+
|
33
33
|
@handshake_complete = true
|
34
|
-
|
34
|
+
|
35
35
|
Digest::MD5.digest(big_endian(value1) +
|
36
36
|
big_endian(value2) +
|
37
37
|
head)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def open?
|
41
41
|
!!@handshake_complete
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def parse(data)
|
45
45
|
return super if @handshake_complete
|
46
46
|
handshake_signature(data)
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def close(code = nil, reason = nil, &callback)
|
50
50
|
return if @closed
|
51
51
|
@socket.send([0xFF, 0x00]) if @closing
|
52
52
|
@closed = true
|
53
53
|
callback.call if callback
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
private
|
57
|
-
|
57
|
+
|
58
58
|
def parse_leading_byte(data)
|
59
59
|
return super unless data == 0xFF
|
60
60
|
@closing = true
|
61
61
|
@length = 0
|
62
62
|
@stage = 1
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
def number_from_key(key)
|
66
66
|
key.scan(/[0-9]/).join('').to_i(10)
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def spaces_in_key(key)
|
70
70
|
key.scan(/ /).size
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def big_endian(number)
|
74
74
|
string = ''
|
75
75
|
[24,16,8,0].each do |offset|
|
@@ -78,7 +78,7 @@ module Faye
|
|
78
78
|
string
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|