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.

Files changed (54) hide show
  1. data/History.txt +15 -3
  2. data/README.rdoc +2 -6
  3. data/lib/faye-browser-min.js +1 -1
  4. data/lib/faye.rb +25 -36
  5. data/lib/faye/adapters/rack_adapter.rb +43 -22
  6. data/lib/faye/engines/connection.rb +7 -10
  7. data/lib/faye/engines/memory.rb +28 -28
  8. data/lib/faye/engines/proxy.rb +109 -0
  9. data/lib/faye/mixins/logging.rb +1 -8
  10. data/lib/faye/mixins/timeouts.rb +1 -1
  11. data/lib/faye/protocol/channel.rb +3 -3
  12. data/lib/faye/protocol/client.rb +50 -45
  13. data/lib/faye/protocol/extensible.rb +11 -18
  14. data/lib/faye/protocol/server.rb +53 -38
  15. data/lib/faye/transport/http.rb +49 -27
  16. data/lib/faye/transport/transport.rb +3 -1
  17. data/lib/faye/transport/web_socket.rb +6 -10
  18. data/lib/faye/util/namespace.rb +2 -2
  19. data/spec/browser.html +3 -1
  20. data/spec/encoding_helper.rb +7 -0
  21. data/spec/javascript/client_spec.js +0 -5
  22. data/spec/javascript/engine/memory_spec.js +7 -0
  23. data/spec/javascript/engine_spec.js +22 -57
  24. data/spec/javascript/server/handshake_spec.js +10 -6
  25. data/spec/javascript/server/integration_spec.js +11 -10
  26. data/spec/javascript/server/publish_spec.js +85 -0
  27. data/spec/javascript/server_spec.js +5 -51
  28. data/spec/node.js +6 -6
  29. data/spec/ruby/client_spec.rb +1 -1
  30. data/spec/ruby/engine/memory_spec.rb +7 -0
  31. data/spec/ruby/{engine_spec.rb → engine_examples.rb} +28 -34
  32. data/spec/ruby/rack_adapter_spec.rb +1 -1
  33. data/spec/ruby/server/handshake_spec.rb +10 -6
  34. data/spec/ruby/server/publish_spec.rb +81 -0
  35. data/spec/ruby/server_spec.rb +6 -44
  36. data/spec/spec_helper.rb +5 -18
  37. data/spec/testswarm +1 -5
  38. metadata +105 -180
  39. data/lib/faye/engines/base.rb +0 -66
  40. data/lib/faye/engines/redis.rb +0 -225
  41. data/lib/faye/thin_extensions.rb +0 -75
  42. data/lib/faye/util/web_socket.rb +0 -89
  43. data/lib/faye/util/web_socket/api.rb +0 -103
  44. data/lib/faye/util/web_socket/client.rb +0 -82
  45. data/lib/faye/util/web_socket/draft75_parser.rb +0 -53
  46. data/lib/faye/util/web_socket/draft76_parser.rb +0 -53
  47. data/lib/faye/util/web_socket/protocol8_parser.rb +0 -324
  48. data/spec/javascript/web_socket/client_spec.js +0 -121
  49. data/spec/javascript/web_socket/draft75parser_spec.js +0 -39
  50. data/spec/javascript/web_socket/protocol8parser_spec.js +0 -153
  51. data/spec/redis.conf +0 -42
  52. data/spec/ruby/web_socket/client_spec.rb +0 -126
  53. data/spec/ruby/web_socket/draft75_parser_spec.rb +0 -41
  54. 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
-