mirror of
https://github.com/samsonjs/rack-attack.git
synced 2026-03-25 09:25:49 +00:00
Refactor StoreProxy to avoid autoloading MemCacheStore
In v4.4.0, checking `defined?(ActiveSupport::Cache::MemCacheStore)`
could trigger an error loading dalli, which isn’t needed.
This fixes that bug, and prevents similar bugs by checking
`store.class.to_s` rather than `defined?(klass) && store.is_a?(klass)`.
Writing an automated test to ensure that dalli is truly optional is
difficult, but I was able to recreate the dalli load error in v4.4.0 by
running:
gem uninstall dalli
ruby -Ilib -ractive_support/all -ractive_support/cache/redis_store
-rrack/attack -e 'p Rack::Attack::StoreProxy.build(Redis::Store.new)'
Fixes #163
This commit is contained in:
parent
14c7020242
commit
9d90610bbe
1 changed files with 21 additions and 17 deletions
|
|
@ -3,26 +3,30 @@ module Rack
|
|||
module StoreProxy
|
||||
PROXIES = [DalliProxy, MemCacheProxy, RedisStoreProxy]
|
||||
|
||||
def self.build(store)
|
||||
# RedisStore#increment needs different behavior, so detect that
|
||||
# (method has an arity of 2; must call #expire separately
|
||||
if (defined?(::ActiveSupport::Cache::RedisStore) && store.is_a?(::ActiveSupport::Cache::RedisStore)) ||
|
||||
(defined?(::ActiveSupport::Cache::MemCacheStore) && store.is_a?(::ActiveSupport::Cache::MemCacheStore))
|
||||
ACTIVE_SUPPORT_WRAPPER_CLASSES = Set.new(['ActiveSupport::Cache::MemCacheStore', 'ActiveSupport::Cache::RedisStore']).freeze
|
||||
ACTIVE_SUPPORT_CLIENTS = Set.new(['Redis::Store', 'Dalli::Client', 'MemCache']).freeze
|
||||
|
||||
# ActiveSupport::Cache::RedisStore doesn't expose any way to set an expiry,
|
||||
# so use the raw Redis::Store instead.
|
||||
# We also want to use the underlying Dalli client instead of ::ActiveSupport::Cache::MemCacheStore,
|
||||
# and the MemCache client if using Rails 3.x
|
||||
client = store.instance_variable_get(:@data)
|
||||
if (defined?(::Redis::Store) && client.is_a?(Redis::Store)) ||
|
||||
(defined?(Dalli::Client) && client.is_a?(Dalli::Client)) || (defined?(MemCache) && client.is_a?(MemCache))
|
||||
store = store.instance_variable_get(:@data)
|
||||
end
|
||||
end
|
||||
klass = PROXIES.find { |proxy| proxy.handle?(store) }
|
||||
klass ? klass.new(store) : store
|
||||
def self.build(store)
|
||||
client = unwrap_active_support_stores(store)
|
||||
klass = PROXIES.find { |proxy| proxy.handle?(client) }
|
||||
klass ? klass.new(client) : client
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def self.unwrap_active_support_stores(store)
|
||||
# ActiveSupport::Cache::RedisStore doesn't expose any way to set an expiry,
|
||||
# so use the raw Redis::Store instead.
|
||||
# We also want to use the underlying Dalli client instead of ::ActiveSupport::Cache::MemCacheStore,
|
||||
# and the MemCache client if using Rails 3.x
|
||||
|
||||
client = store.instance_variable_get(:@data)
|
||||
if ACTIVE_SUPPORT_WRAPPER_CLASSES.include?(store.class.to_s) && ACTIVE_SUPPORT_CLIENTS.include?(client.class.to_s)
|
||||
client
|
||||
else
|
||||
store
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue