[Fix #28751] Hash stream long stream identifiers when using Postgres adapter

This commit is contained in:
palkan 2017-07-06 17:34:05 +03:00
parent c8ce345964
commit 2bce7777b7
3 changed files with 31 additions and 3 deletions

View File

@ -1,3 +1,12 @@
* Hash long stream identifiers when using Postgres adapter.
PostgreSQL has a limit on identifiers length (63 chars, [docs](https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)).
Provided fix minifies identifiers longer than 63 chars by hashing them with SHA1.
Fixes #28751.
*Vladimir Dementyev*
* ActionCable's `redis` adapter allows for other common redis-rb options (`host`, `port`, `db`, `password`) in cable.yml.
Previously, it accepts only a [redis:// url](https://www.iana.org/assignments/uri-schemes/prov/redis) as an option.

View File

@ -1,6 +1,7 @@
gem "pg", "~> 0.18"
require "pg"
require "thread"
require "digest/sha1"
module ActionCable
module SubscriptionAdapter
@ -12,16 +13,16 @@ module ActionCable
def broadcast(channel, payload)
with_connection do |pg_conn|
pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel)}, '#{pg_conn.escape_string(payload)}'")
pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel_identifier(channel))}, '#{pg_conn.escape_string(payload)}'")
end
end
def subscribe(channel, callback, success_callback = nil)
listener.add_subscriber(channel, callback, success_callback)
listener.add_subscriber(channel_identifier(channel), callback, success_callback)
end
def unsubscribe(channel, callback)
listener.remove_subscriber(channel, callback)
listener.remove_subscriber(channel_identifier(channel), callback)
end
def shutdown
@ -41,6 +42,10 @@ module ActionCable
end
private
def channel_identifier(channel)
channel.size > 63 ? Digest::SHA1.hexdigest(channel) : channel
end
def listener
@listener || @server.mutex.synchronize { @listener ||= Listener.new(self, @server.event_loop) }
end

View File

@ -112,4 +112,18 @@ module CommonSubscriptionAdapterTest
assert_equal "two", queue.pop
end
end
def test_long_identifiers
channel_1 = "a" * 100 + "1"
channel_2 = "a" * 100 + "2"
subscribe_as_queue(channel_1) do |queue|
subscribe_as_queue(channel_2) do |queue_2|
@tx_adapter.broadcast(channel_1, "apples")
@tx_adapter.broadcast(channel_2, "oranges")
assert_equal "apples", queue.pop
assert_equal "oranges", queue_2.pop
end
end
end
end