aboutsummaryrefslogtreecommitdiffstats
path: root/actioncable
diff options
context:
space:
mode:
Diffstat (limited to 'actioncable')
-rw-r--r--actioncable/README.md10
-rw-r--r--actioncable/app/assets/javascripts/action_cable.coffee.erb2
-rw-r--r--actioncable/app/assets/javascripts/action_cable/connection.coffee4
-rw-r--r--actioncable/lib/action_cable/channel/base.rb2
-rw-r--r--actioncable/lib/action_cable/channel/streams.rb2
-rw-r--r--actioncable/lib/action_cable/connection/client_socket.rb8
-rw-r--r--actioncable/lib/action_cable/connection/stream.rb18
-rw-r--r--actioncable/lib/action_cable/engine.rb13
-rw-r--r--actioncable/lib/action_cable/helpers/action_cable_helper.rb27
-rw-r--r--actioncable/lib/action_cable/server/configuration.rb2
-rw-r--r--actioncable/lib/action_cable/subscription_adapter/redis.rb8
-rw-r--r--actioncable/test/connection/base_test.rb20
12 files changed, 82 insertions, 34 deletions
diff --git a/actioncable/README.md b/actioncable/README.md
index 334c75c79c..bb15ad3c70 100644
--- a/actioncable/README.md
+++ b/actioncable/README.md
@@ -339,21 +339,21 @@ Rails.application.config.action_cable.disable_request_forgery_protection = true
### Consumer Configuration
-Once you have decided how to run your cable server (see below), you must provide the server url (or path) to your client-side setup.
+Once you have decided how to run your cable server (see below), you must provide the server URL (or path) to your client-side setup.
There are two ways you can do this.
The first is to simply pass it in when creating your consumer. For a standalone server,
this would be something like: `App.cable = ActionCable.createConsumer("ws://example.com:28080")`, and for an in-app server,
something like: `App.cable = ActionCable.createConsumer("/cable")`.
-The second option is to pass the server url through the `action_cable_meta_tag` in your layout.
-This uses a url or path typically set via `config.action_cable.url` in the environment configuration files, or defaults to "/cable".
+The second option is to pass the server URL through the `action_cable_meta_tag` in your layout.
+This uses a URL or path typically set via `config.action_cable.url` in the environment configuration files, or defaults to "/cable".
-This method is especially useful if your WebSocket url might change between environments. If you host your production server via https, you will need to use the wss scheme
+This method is especially useful if your WebSocket URL might change between environments. If you host your production server via https, you will need to use the wss scheme
for your Action Cable server, but development might remain http and use the ws scheme. You might use localhost in development and your
domain in production.
-In any case, to vary the WebSocket url between environments, add the following configuration to each environment:
+In any case, to vary the WebSocket URL between environments, add the following configuration to each environment:
```ruby
config.action_cable.url = "ws://example.com:28080"
diff --git a/actioncable/app/assets/javascripts/action_cable.coffee.erb b/actioncable/app/assets/javascripts/action_cable.coffee.erb
index d95fe78ac5..6a8b4eeb85 100644
--- a/actioncable/app/assets/javascripts/action_cable.coffee.erb
+++ b/actioncable/app/assets/javascripts/action_cable.coffee.erb
@@ -9,7 +9,7 @@
getConfig: (name) ->
element = document.head.querySelector("meta[name='action-cable-#{name}']")
- element?.getAttribute("content")
+ element?.getAttribute("content") ? '/cable'
createWebSocketURL: (url) ->
if url and not /^wss?:/i.test(url)
diff --git a/actioncable/app/assets/javascripts/action_cable/connection.coffee b/actioncable/app/assets/javascripts/action_cable/connection.coffee
index ee888f567b..4244322a1e 100644
--- a/actioncable/app/assets/javascripts/action_cable/connection.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/connection.coffee
@@ -6,9 +6,11 @@ class ActionCable.Connection
@reopenDelay: 500
constructor: (@consumer) ->
- @open()
send: (data) ->
+ unless @isOpen()
+ @open()
+
if @isOpen()
@webSocket.send(JSON.stringify(data))
true
diff --git a/actioncable/lib/action_cable/channel/base.rb b/actioncable/lib/action_cable/channel/base.rb
index 05764fe107..714d9887d4 100644
--- a/actioncable/lib/action_cable/channel/base.rb
+++ b/actioncable/lib/action_cable/channel/base.rb
@@ -166,7 +166,7 @@ module ActionCable
end
end
- # Called by the cable connection when its cut, so the channel has a chance to cleanup with callbacks.
+ # Called by the cable connection when it's cut, so the channel has a chance to cleanup with callbacks.
# This method is not intended to be called directly by the user. Instead, overwrite the #unsubscribed callback.
def unsubscribe_from_channel # :nodoc:
run_callbacks :unsubscribe do
diff --git a/actioncable/lib/action_cable/channel/streams.rb b/actioncable/lib/action_cable/channel/streams.rb
index 28092a8b2b..431a5c1063 100644
--- a/actioncable/lib/action_cable/channel/streams.rb
+++ b/actioncable/lib/action_cable/channel/streams.rb
@@ -1,6 +1,6 @@
module ActionCable
module Channel
- # Streams allow channels to route broadcastings to the subscriber. A broadcasting is, as discussed elsewhere, a pub/sub queue where any data
+ # Streams allow channels to route broadcastings to the subscriber. A broadcasting is, as discussed elsewhere, a pubsub queue where any data
# placed into it is automatically sent to the clients that are connected at that time. It's purely an online queue, though. If you're not
# streaming a broadcasting at the very moment it sends out an update, you will not get that update, if you connect after it has been sent.
#
diff --git a/actioncable/lib/action_cable/connection/client_socket.rb b/actioncable/lib/action_cable/connection/client_socket.rb
index 95e1ac4c16..f6b11e93f0 100644
--- a/actioncable/lib/action_cable/connection/client_socket.rb
+++ b/actioncable/lib/action_cable/connection/client_socket.rb
@@ -50,14 +50,16 @@ module ActionCable
@driver.on(:error) { |e| emit_error(e.message) }
@stream = ActionCable::Connection::Stream.new(@stream_event_loop, self)
+ end
+
+ def start_driver
+ return if @driver.nil? || @driver_started
+ @stream.hijack_rack_socket
if callback = @env['async.callback']
callback.call([101, {}, @stream])
end
- end
- def start_driver
- return if @driver.nil? || @driver_started
@driver_started = true
@driver.start
end
diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb
index ace250cd16..2d97b28c09 100644
--- a/actioncable/lib/action_cable/connection/stream.rb
+++ b/actioncable/lib/action_cable/connection/stream.rb
@@ -4,15 +4,13 @@ module ActionCable
# This class is heavily based on faye-websocket-ruby
#
# Copyright (c) 2010-2015 James Coglan
- class Stream
+ class Stream # :nodoc:
def initialize(event_loop, socket)
@event_loop = event_loop
@socket_object = socket
@stream_send = socket.env['stream.send']
@rack_hijack_io = nil
-
- hijack_rack_socket
end
def each(&callback)
@@ -39,16 +37,16 @@ module ActionCable
@socket_object.parse(data)
end
- private
- def hijack_rack_socket
- return unless @socket_object.env['rack.hijack']
+ def hijack_rack_socket
+ return unless @socket_object.env['rack.hijack']
- @socket_object.env['rack.hijack'].call
- @rack_hijack_io = @socket_object.env['rack.hijack_io']
+ @socket_object.env['rack.hijack'].call
+ @rack_hijack_io = @socket_object.env['rack.hijack_io']
- @event_loop.attach(@rack_hijack_io, self)
- end
+ @event_loop.attach(@rack_hijack_io, self)
+ end
+ private
def clean_rack_hijack
return unless @rack_hijack_io
@event_loop.detach(@rack_hijack_io, self)
diff --git a/actioncable/lib/action_cable/engine.rb b/actioncable/lib/action_cable/engine.rb
index f5f1cb59e0..ae0c59dccd 100644
--- a/actioncable/lib/action_cable/engine.rb
+++ b/actioncable/lib/action_cable/engine.rb
@@ -6,7 +6,7 @@ require "active_support/core_ext/hash/indifferent_access"
module ActionCable
class Railtie < Rails::Engine # :nodoc:
config.action_cable = ActiveSupport::OrderedOptions.new
- config.action_cable.url = '/cable'
+ config.action_cable.mount_path = '/cable'
config.eager_load_namespaces << ActionCable
@@ -40,5 +40,16 @@ module ActionCable
options.each { |k,v| send("#{k}=", v) }
end
end
+
+ initializer "action_cable.routes" do
+ config.after_initialize do |app|
+ config = app.config
+ unless config.action_cable.mount_path.nil?
+ app.routes.prepend do
+ mount ActionCable.server => config.action_cable.mount_path, internal: true
+ end
+ end
+ end
+ end
end
end
diff --git a/actioncable/lib/action_cable/helpers/action_cable_helper.rb b/actioncable/lib/action_cable/helpers/action_cable_helper.rb
index 3067542b33..2081a37db6 100644
--- a/actioncable/lib/action_cable/helpers/action_cable_helper.rb
+++ b/actioncable/lib/action_cable/helpers/action_cable_helper.rb
@@ -1,28 +1,39 @@
module ActionCable
module Helpers
module ActionCableHelper
- # Returns an "action-cable-url" meta tag with the value of the url specified in your
- # configuration. Ensure this is above your javascript tag:
+ # Returns an "action-cable-url" meta tag with the value of the URL specified in your
+ # configuration. Ensure this is above your JavaScript tag:
#
# <head>
# <%= action_cable_meta_tag %>
# <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
# </head>
#
- # This is then used by Action Cable to determine the url of your WebSocket server.
+ # This is then used by Action Cable to determine the URL of your WebSocket server.
# Your CoffeeScript can then connect to the server without needing to specify the
- # url directly:
+ # URL directly:
#
# #= require cable
# @App = {}
# App.cable = Cable.createConsumer()
#
- # Make sure to specify the correct server location in each of your environments
- # config file:
+ # Make sure to specify the correct server location in each of your environment
+ # config files:
+ #
+ # config.action_cable.mount_path = "/cable123"
+ # <%= action_cable_meta_tag %> would render:
+ # => <meta name="action-cable-url" content="/cable123" />
+ #
+ # config.action_cable.url = "ws://actioncable.com"
+ # <%= action_cable_meta_tag %> would render:
+ # => <meta name="action-cable-url" content="ws://actioncable.com" />
#
- # config.action_cable.url = "ws://example.com:28080"
def action_cable_meta_tag
- tag "meta", name: "action-cable-url", content: Rails.application.config.action_cable.url
+ tag "meta", name: "action-cable-url", content: (
+ ActionCable.server.config.url ||
+ ActionCable.server.config.mount_path ||
+ raise("No Action Cable URL configured -- please configure this at config.action_cable.url")
+ )
end
end
end
diff --git a/actioncable/lib/action_cable/server/configuration.rb b/actioncable/lib/action_cable/server/configuration.rb
index ee17bff13b..9a7301287c 100644
--- a/actioncable/lib/action_cable/server/configuration.rb
+++ b/actioncable/lib/action_cable/server/configuration.rb
@@ -6,7 +6,7 @@ module ActionCable
attr_accessor :logger, :log_tags
attr_accessor :connection_class, :worker_pool_size
attr_accessor :disable_request_forgery_protection, :allowed_request_origins
- attr_accessor :cable, :url
+ attr_accessor :cable, :url, :mount_path
attr_accessor :channel_paths # :nodoc:
diff --git a/actioncable/lib/action_cable/subscription_adapter/redis.rb b/actioncable/lib/action_cable/subscription_adapter/redis.rb
index ba4934a264..6b4236e7d3 100644
--- a/actioncable/lib/action_cable/subscription_adapter/redis.rb
+++ b/actioncable/lib/action_cable/subscription_adapter/redis.rb
@@ -33,7 +33,7 @@ module ActionCable
end
def redis_connection_for_subscriptions
- ::Redis.new(@server.config.cable)
+ redis_connection
end
private
@@ -43,10 +43,14 @@ module ActionCable
def redis_connection_for_broadcasts
@redis_connection_for_broadcasts || @server.mutex.synchronize do
- @redis_connection_for_broadcasts ||= self.class.redis_connector.call(@server.config.cable)
+ @redis_connection_for_broadcasts ||= redis_connection
end
end
+ def redis_connection
+ self.class.redis_connector.call(@server.config.cable)
+ end
+
class Listener < SubscriberMap
def initialize(adapter)
super()
diff --git a/actioncable/test/connection/base_test.rb b/actioncable/test/connection/base_test.rb
index 3bef9e95a1..fb11f9be64 100644
--- a/actioncable/test/connection/base_test.rb
+++ b/actioncable/test/connection/base_test.rb
@@ -108,6 +108,26 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase
end
end
+ test "rejecting a connection causes a 404" do
+ run_in_eventmachine do
+ class CallMeMaybe
+ def call(*)
+ raise 'Do not call me!'
+ end
+ end
+
+ env = Rack::MockRequest.env_for(
+ "/test",
+ { 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',
+ 'HTTP_ORIGIN' => 'http://rubyonrails.org', 'rack.hijack' => CallMeMaybe.new }
+ )
+
+ connection = ActionCable::Connection::Base.new(@server, env)
+ response = connection.process
+ assert_equal 404, response[0]
+ end
+ end
+
private
def open_connection
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',