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.

Files changed (38) hide show
  1. data/CHANGELOG.md +81 -0
  2. data/README.md +408 -0
  3. data/examples/app.rb +4 -1
  4. data/examples/autobahn_client.rb +8 -6
  5. data/examples/client.rb +2 -1
  6. data/examples/config.ru +6 -9
  7. data/{spec → examples}/rainbows.conf +0 -0
  8. data/examples/server.rb +10 -1
  9. data/lib/faye/adapters/rainbows.rb +15 -16
  10. data/lib/faye/adapters/rainbows_client.rb +15 -16
  11. data/lib/faye/adapters/thin.rb +15 -16
  12. data/lib/faye/eventsource.rb +38 -46
  13. data/lib/faye/rack_stream.rb +70 -0
  14. data/lib/faye/websocket.rb +39 -162
  15. data/lib/faye/websocket/api.rb +70 -60
  16. data/lib/faye/websocket/api/event.rb +1 -1
  17. data/lib/faye/websocket/api/event_target.rb +35 -12
  18. data/lib/faye/websocket/client.rb +5 -38
  19. metadata +62 -45
  20. data/CHANGELOG.txt +0 -74
  21. data/README.rdoc +0 -366
  22. data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +0 -61
  23. data/ext/faye_websocket_mask/extconf.rb +0 -5
  24. data/ext/faye_websocket_mask/faye_websocket_mask.c +0 -33
  25. data/lib/faye/websocket/draft75_parser.rb +0 -87
  26. data/lib/faye/websocket/draft76_parser.rb +0 -84
  27. data/lib/faye/websocket/hybi_parser.rb +0 -321
  28. data/lib/faye/websocket/hybi_parser/handshake.rb +0 -78
  29. data/lib/faye/websocket/hybi_parser/stream_reader.rb +0 -29
  30. data/lib/faye/websocket/utf8_match.rb +0 -8
  31. data/spec/faye/websocket/client_spec.rb +0 -162
  32. data/spec/faye/websocket/draft75_parser_examples.rb +0 -48
  33. data/spec/faye/websocket/draft75_parser_spec.rb +0 -27
  34. data/spec/faye/websocket/draft76_parser_spec.rb +0 -34
  35. data/spec/faye/websocket/hybi_parser_spec.rb +0 -149
  36. data/spec/server.crt +0 -15
  37. data/spec/server.key +0 -15
  38. data/spec/spec_helper.rb +0 -68
data/examples/app.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path('../../lib/faye/websocket', __FILE__)
1
+ require 'faye/websocket'
2
2
  require 'rack'
3
3
 
4
4
  static = Rack::File.new(File.dirname(__FILE__))
@@ -48,3 +48,6 @@ App = lambda do |env|
48
48
  end
49
49
  end
50
50
 
51
+ def App.log(message)
52
+ end
53
+
@@ -1,13 +1,15 @@
1
1
  require 'rubygems'
2
- require File.expand_path('../../lib/faye/websocket', __FILE__)
2
+ require 'bundler/setup'
3
+ require 'faye/websocket'
3
4
  require 'cgi'
4
5
  require 'progressbar'
5
6
 
6
7
  EM.run {
7
- host = 'ws://localhost:9001'
8
- agent = "Ruby #{RUBY_VERSION}"
9
- cases = 0
10
- skip = []
8
+ host = 'ws://localhost:9001'
9
+ ruby = RUBY_PLATFORM =~ /java/ ? 'JRuby' : 'MRI'
10
+ agent = "#{ruby} #{RUBY_VERSION}"
11
+ cases = 0
12
+ skip = []
11
13
 
12
14
  socket = Faye::WebSocket::Client.new("#{host}/getCaseCount")
13
15
  progress = nil
@@ -37,7 +39,7 @@ EM.run {
37
39
  socket.send(event.data)
38
40
  end
39
41
 
40
- socket.onclose = lambda do |event|
42
+ socket.on :close do |event|
41
43
  run_case.call(n + 1)
42
44
  end
43
45
  end
data/examples/client.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
- require File.expand_path('../../lib/faye/websocket', __FILE__)
2
+ require 'bundler/setup'
3
+ require 'faye/websocket'
3
4
  require 'eventmachine'
4
5
 
5
6
  port = ARGV[0] || 7000
data/examples/config.ru CHANGED
@@ -1,17 +1,14 @@
1
- # Run using your favourite async server:
1
+ # Run using your favourite server:
2
2
  #
3
3
  # thin start -R examples/config.ru -p 7000
4
- # rainbows -c spec/rainbows.conf -E production examples/config.ru -p 7000
5
- #
6
- # If you run using one of these commands, the webserver is loaded before this
7
- # file, so Faye::WebSocket can figure out which adapter to load. If instead you
8
- # run using `rackup`, you need the `load_adapter` line below.
9
- #
10
- # rackup -E production -s thin examples/config.ru -p 7000
4
+ # rainbows -c examples/rainbows.conf -E production examples/config.ru -p 7000
11
5
 
12
6
  require 'rubygems'
7
+ require 'bundler/setup'
13
8
  require File.expand_path('../app', __FILE__)
14
- # Faye::WebSocket.load_adapter('thin')
9
+
10
+ Faye::WebSocket.load_adapter('thin')
11
+ Faye::WebSocket.load_adapter('rainbows')
15
12
 
16
13
  run App
17
14
 
File without changes
data/examples/server.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rubygems'
2
+ require 'bundler/setup'
2
3
  require 'rack/content_length'
3
4
  require 'rack/chunked'
4
5
 
@@ -19,12 +20,20 @@ when 'goliath'
19
20
  end
20
21
  end
21
22
 
23
+ when 'puma'
24
+ events = Puma::Events.new($stdout, $stderr)
25
+ binder = Puma::Binder.new(events)
26
+ binder.parse(["tcp://0.0.0.0:#{port}"], App)
27
+ server = Puma::Server.new(App, events)
28
+ server.binder = binder
29
+ server.run.join
30
+
22
31
  when 'rainbows'
23
32
  rackup = Unicorn::Configurator::RACKUP
24
33
  rackup[:port] = port
25
34
  rackup[:set_listener] = true
26
35
  options = rackup[:options]
27
- options[:config_file] = spec + '/rainbows.conf'
36
+ options[:config_file] = File.expand_path('../rainbows.conf', __FILE__)
28
37
  Rainbows::HttpServer.new(App, options).start.join
29
38
 
30
39
  when 'thin'
@@ -4,24 +4,23 @@
4
4
 
5
5
  # Copyright (c) 2009-2011 Pratik Naik
6
6
  #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
14
13
  #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
17
16
  #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
25
24
 
26
25
  module Faye
27
26
  class WebSocket
@@ -4,24 +4,23 @@
4
4
 
5
5
  # Copyright (c) 2009-2011 Pratik Naik
6
6
  #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
14
13
  #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
17
16
  #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
25
24
 
26
25
  module Faye
27
26
  class WebSocket
@@ -4,24 +4,23 @@
4
4
 
5
5
  # Copyright (c) 2009-2011 Pratik Naik
6
6
  #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
14
13
  #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
17
16
  #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
25
24
 
26
25
  class Thin::Connection
27
26
  attr_accessor :socket_stream
@@ -2,40 +2,39 @@ require File.expand_path('../websocket', __FILE__) unless defined?(Faye::WebSock
2
2
 
3
3
  module Faye
4
4
  class EventSource
5
- DEFAULT_RETRY = 5
6
5
 
7
- include WebSocket::API
6
+ include WebSocket::API::EventTarget
8
7
  attr_reader :env, :url, :ready_state
9
8
 
9
+ DEFAULT_RETRY = 5
10
+
10
11
  def self.eventsource?(env)
12
+ return false unless env['REQUEST_METHOD'] == 'GET'
11
13
  accept = (env['HTTP_ACCEPT'] || '').split(/\s*,\s*/)
12
14
  accept.include?('text/event-stream')
13
15
  end
14
16
 
15
17
  def self.determine_url(env)
16
- secure = if env.has_key?('HTTP_X_FORWARDED_PROTO')
17
- env['HTTP_X_FORWARDED_PROTO'] == 'https'
18
- else
19
- env['HTTP_ORIGIN'] =~ /^https:/i
20
- end
21
-
18
+ secure = Rack::Request.new(env).ssl?
22
19
  scheme = secure ? 'https:' : 'http:'
23
20
  "#{ scheme }//#{ env['HTTP_HOST'] }#{ env['REQUEST_URI'] }"
24
21
  end
25
22
 
26
23
  def initialize(env, options = {})
24
+ WebSocket.ensure_reactor_running
25
+ super()
26
+
27
27
  @env = env
28
28
  @ping = options[:ping]
29
29
  @retry = (options[:retry] || DEFAULT_RETRY).to_f
30
30
  @url = EventSource.determine_url(env)
31
31
  @stream = Stream.new(self)
32
32
 
33
- @ready_state = CONNECTING
34
- @send_buffer = []
35
- EventMachine.next_tick { open }
33
+ @ready_state = WebSocket::API::CONNECTING
36
34
 
37
- callback = @env['async.callback']
38
- callback.call([101, {}, @stream])
35
+ if callback = @env['async.callback']
36
+ callback.call([101, {}, @stream])
37
+ end
39
38
 
40
39
  @stream.write("HTTP/1.1 200 OK\r\n" +
41
40
  "Content-Type: text/event-stream\r\n" +
@@ -44,7 +43,7 @@ module Faye
44
43
  "\r\n\r\n" +
45
44
  "retry: #{ (@retry * 1000).floor }\r\n\r\n")
46
45
 
47
- @ready_state = OPEN
46
+ EventMachine.next_tick { open }
48
47
 
49
48
  if @ping
50
49
  @ping_timer = EventMachine.add_periodic_timer(@ping) { ping }
@@ -59,10 +58,24 @@ module Faye
59
58
  [ -1, {}, [] ]
60
59
  end
61
60
 
61
+ private
62
+
63
+ def open
64
+ return unless @ready_state == WebSocket::API::CONNECTING
65
+
66
+ @ready_state = WebSocket::API::OPEN
67
+
68
+ event = WebSocket::API::Event.new('open')
69
+ event.init_event('open', false, false)
70
+ dispatch_event(event)
71
+ end
72
+
73
+ public
74
+
62
75
  def send(message, options = {})
63
- return false unless @ready_state == OPEN
76
+ return false if @ready_state > WebSocket::API::OPEN
64
77
 
65
- message = WebSocket.encode(message.to_s).
78
+ message = ::WebSocket::Driver.encode(message.to_s).
66
79
  gsub(/(\r\n|\r|\n)/, '\1data: ')
67
80
 
68
81
  frame = ""
@@ -75,50 +88,29 @@ module Faye
75
88
  end
76
89
 
77
90
  def ping(message = nil)
91
+ return false if @ready_state > WebSocket::API::OPEN
78
92
  @stream.write(":\r\n\r\n")
79
93
  true
80
94
  end
81
95
 
82
96
  def close
83
- return if [CLOSING, CLOSED].include?(@ready_state)
84
- @ready_state = CLOSED
97
+ return if [WebSocket::API::CLOSING, WebSocket::API::CLOSED].include?(@ready_state)
98
+
99
+ @ready_state = WebSocket::API::CLOSED
85
100
  EventMachine.cancel_timer(@ping_timer)
86
101
  @stream.close_connection_after_writing
102
+
87
103
  event = WebSocket::API::Event.new('close')
88
104
  event.init_event('close', false, false)
89
105
  dispatch_event(event)
90
106
  end
91
- end
92
-
93
- class EventSource::Stream
94
- include EventMachine::Deferrable
95
-
96
- extend Forwardable
97
- def_delegators :@connection, :close_connection, :close_connection_after_writing
98
-
99
- def initialize(event_source)
100
- @event_source = event_source
101
- @connection = event_source.env['em.connection']
102
- @stream_send = event_source.env['stream.send']
103
-
104
- @connection.socket_stream = self if @connection.respond_to?(:socket_stream)
105
- end
106
-
107
- def each(&callback)
108
- @stream_send ||= callback
109
- end
110
107
 
111
- def fail
112
- @event_source.close
113
- end
114
-
115
- def receive(data)
108
+ class Stream < RackStream
109
+ def fail
110
+ @socket_object.close
111
+ end
116
112
  end
117
113
 
118
- def write(data)
119
- return unless @stream_send
120
- @stream_send.call(data) rescue nil
121
- end
122
114
  end
123
115
  end
124
116
 
@@ -0,0 +1,70 @@
1
+ module Faye
2
+ class RackStream
3
+
4
+ include EventMachine::Deferrable
5
+
6
+ module Reader
7
+ attr_accessor :stream
8
+
9
+ def receive_data(data)
10
+ stream.receive(data)
11
+ end
12
+
13
+ def unbind
14
+ stream.fail
15
+ end
16
+ end
17
+
18
+ def initialize(socket_object)
19
+ @socket_object = socket_object
20
+ @connection = socket_object.env['em.connection']
21
+ @stream_send = socket_object.env['stream.send']
22
+
23
+ if socket_object.env['rack.hijack']
24
+ socket_object.env['rack.hijack'].call
25
+ @rack_hijack_io = socket_object.env['rack.hijack_io']
26
+ EventMachine.attach(@rack_hijack_io, Reader) do |reader|
27
+ @rack_hijack_io_reader = reader
28
+ reader.stream = self
29
+ end
30
+ end
31
+
32
+ @connection.socket_stream = self if @connection.respond_to?(:socket_stream)
33
+ end
34
+
35
+ def clean_rack_hijack
36
+ return unless @rack_hijack_io
37
+ @rack_hijack_io_reader.close_connection_after_writing
38
+ @rack_hijack_io = @rack_hijack_io_reader = nil
39
+ end
40
+
41
+ def close_connection
42
+ clean_rack_hijack
43
+ @connection.close_connection if @connection
44
+ end
45
+
46
+ def close_connection_after_writing
47
+ clean_rack_hijack
48
+ @connection.close_connection_after_writing if @connection
49
+ end
50
+
51
+ def each(&callback)
52
+ @stream_send ||= callback
53
+ end
54
+
55
+ def fail
56
+ end
57
+
58
+ def receive(data)
59
+ end
60
+
61
+ def write(data)
62
+ return @rack_hijack_io.write(data) if @rack_hijack_io
63
+ return @stream_send.call(data) if @stream_send
64
+ rescue => e
65
+ fail if EOFError === e
66
+ end
67
+
68
+ end
69
+ end
70
+