From b168eb5819fa5fea940c9865d5c9a3ec5ba2a7ec Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Fri, 11 Mar 2016 16:32:02 -0700 Subject: Cable message encoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Introduce a connection coder responsible for encoding Cable messages as WebSocket messages, defaulting to `ActiveSupport::JSON` and duck- typing to any object responding to `#encode` and `#decode`. * Consolidate encoding responsibility to the connection. No longer explicitly JSON-encode from channels or other sources. Pass Cable messages as Hashes to `#transmit` and rely on it to encode. * Introduce stream encoders responsible for decoding pubsub messages. Preserve the currently raw encoding, but make it easy to use JSON. Same duck type as the connection encoder. * Revert recent data normalization/quoting (#23649) which treated `identifier` and `data` values as nested JSON objects rather than as opaque JSON-encoded strings. That dealt us an awkward hand where we'd decode JSON strings… or not, but always encode as JSON. Embedding JSON object values directly is preferably, no extra JSON encoding, but that should be a purposeful protocol version change rather than ambiguously, inadvertently supporting multiple message formats. --- .../lib/action_cable/connection/subscriptions.rb | 25 ++++++---------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'actioncable/lib/action_cable/connection/subscriptions.rb') diff --git a/actioncable/lib/action_cable/connection/subscriptions.rb b/actioncable/lib/action_cable/connection/subscriptions.rb index 5aa907c2d3..3742f248d1 100644 --- a/actioncable/lib/action_cable/connection/subscriptions.rb +++ b/actioncable/lib/action_cable/connection/subscriptions.rb @@ -23,13 +23,13 @@ module ActionCable end def add(data) - id_options = decode_hash(data['identifier']) - identifier = normalize_identifier(id_options) + id_key = data['identifier'] + id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access subscription_klass = connection.server.channel_classes[id_options[:channel]] if subscription_klass - subscriptions[identifier] ||= subscription_klass.new(connection, identifier, id_options) + subscriptions[id_key] ||= subscription_klass.new(connection, id_key, id_options) else logger.error "Subscription class not found (#{data.inspect})" end @@ -37,7 +37,7 @@ module ActionCable def remove(data) logger.info "Unsubscribing from channel: #{data['identifier']}" - remove_subscription subscriptions[normalize_identifier(data['identifier'])] + remove_subscription subscriptions[data['identifier']] end def remove_subscription(subscription) @@ -46,7 +46,7 @@ module ActionCable end def perform_action(data) - find(data).perform_action(decode_hash(data['data'])) + find(data).perform_action ActiveSupport::JSON.decode(data['data']) end def identifiers @@ -63,21 +63,8 @@ module ActionCable private delegate :logger, to: :connection - def normalize_identifier(identifier) - identifier = ActiveSupport::JSON.encode(identifier) if identifier.is_a?(Hash) - identifier - end - - # If `data` is a Hash, this means that the original JSON - # sent by the client had no backslashes in it, and does - # not need to be decoded again. - def decode_hash(data) - data = ActiveSupport::JSON.decode(data) unless data.is_a?(Hash) - data.with_indifferent_access - end - def find(data) - if subscription = subscriptions[normalize_identifier(data['identifier'])] + if subscription = subscriptions[data['identifier']] subscription else raise "Unable to find subscription with identifier: #{data['identifier']}" -- cgit v1.2.3