Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Character encoding issues with MemCacheStore in 1.9.2 #219

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion activesupport/lib/active_support/cache/mem_cache_store.rb
Expand Up @@ -158,7 +158,10 @@ def delete_entry(key, options) # :nodoc:

private
def escape_key(key)
key = key.to_s.gsub(ESCAPE_KEY_CHARS){|match| "%#{match.getbyte(0).to_s(16).upcase}"}
# Fix for EncodedKeyCacheBehavior failing tests in caching_test.rb.
key = key.to_s.dup
key = key.force_encoding(ESCAPE_KEY_CHARS.encoding) if key.respond_to?(:encoding) && key.encoding != ESCAPE_KEY_CHARS.encoding
key = key.gsub(ESCAPE_KEY_CHARS){|match| "%#{match.getbyte(0).to_s(16).upcase}"}
key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
key
end
Expand Down
38 changes: 38 additions & 0 deletions activesupport/test/caching_test.rb
Expand Up @@ -352,6 +352,43 @@ def test_really_long_keys
end
end

# https://rails.lighthouseapp.com/projects/8994/tickets/6225-memcachestore-cant-deal-with-umlauts-and-special-characters
# The error is caused by charcter encodings that can't be compared with ASCII-8BIT regular expressions and by special
# characters like the umlaut in UTF-8.
module EncodedKeyCacheBehavior
if defined?(Encoding)
Encoding.list.each do |encoding|
define_method "test_#{encoding.name.underscore}_encoded_values" do
key = "foo".force_encoding(encoding)
assert_equal true, @cache.write(key, "1", :raw => true)
assert_equal "1", @cache.read(key)
assert_equal "1", @cache.fetch(key)
assert_equal true, @cache.delete(key)
assert_equal "2", @cache.fetch(key, :raw => true) { "2" }
assert_equal 3, @cache.increment(key)
assert_equal 2, @cache.decrement(key)
end
end

def test_common_utf8_values
key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8)
assert_equal true, @cache.write(key, "1", :raw => true)
assert_equal "1", @cache.read(key)
assert_equal "1", @cache.fetch(key)
assert_equal true, @cache.delete(key)
assert_equal "2", @cache.fetch(key, :raw => true) { "2" }
assert_equal 3, @cache.increment(key)
assert_equal 2, @cache.decrement(key)
end

def test_retains_encoding
key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8)
assert_equal true, @cache.write(key, "1", :raw => true)
assert_equal Encoding::UTF_8, key.encoding
end
end
end

module CacheDeleteMatchedBehavior
def test_delete_matched
@cache.write("foo", "bar")
Expand Down Expand Up @@ -617,6 +654,7 @@ def setup
include CacheStoreBehavior
include LocalCacheBehavior
include CacheIncrementDecrementBehavior
include EncodedKeyCacheBehavior

def test_raw_values
cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true)
Expand Down