faye-websocket 0.4.7 → 0.5.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-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
+