From feaa0986f33b7c5db81406f5ab5f492dfe169153 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Mon, 26 Jan 2015 15:56:34 -0800 Subject: [PATCH 1/4] force key encoding to binary to avoid UTF-8 issues --- lib/redis/namespace.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redis/namespace.rb b/lib/redis/namespace.rb index 0705321..e923ba1 100644 --- a/lib/redis/namespace.rb +++ b/lib/redis/namespace.rb @@ -488,7 +488,7 @@ def rem_namespace(key) key.each { |k| yielder.yield rem_namespace(k) } end else - key.to_s.sub(/\A#{@namespace}:/, '') + key.to_s.force_encoding("BINARY").sub(/\A#{@namespace}:/, '') end end From 8e3a76ef0d0ef91f7682a9ee8c00a2ca89ef9002 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 27 Jan 2015 13:30:40 -0800 Subject: [PATCH 2/4] add failing test demonstrating the problem with invalid utf-8 keys --- spec/redis_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/redis_spec.rb b/spec/redis_spec.rb index 0499518..17ae64a 100644 --- a/spec/redis_spec.rb +++ b/spec/redis_spec.rb @@ -366,6 +366,12 @@ @namespaced['foo'].should eq(nil) end + it "should not throw exception on invalid UTF-8 sequences in keys" do + @namespaced.set("f\xFCo", 'bar') + @namespaced.set("foo", 'bar') + @namespaced.keys.should eq ["f\xFCo", "foo"] + end + it "should respond to :namespace=" do @namespaced.respond_to?(:namespace=).should eq(true) end From abed8011ba471956d79c9ed0c35674f7c3dcedd6 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 27 Jan 2015 14:49:27 -0800 Subject: [PATCH 3/4] better fix for UTF-8 keys issue This fixes the frozen string issue from before. Ruby 1.8.7 doesn't support string encoding, so just skip this fanciness for that version. Updates the tests to demonstrate setting a key with invalid UTF-8 chars, getting a list of the keys (including the invalid string) and retrieving the data at those keys. --- lib/redis/namespace.rb | 9 ++++++++- spec/redis_spec.rb | 12 +++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/redis/namespace.rb b/lib/redis/namespace.rb index e923ba1..0fac1da 100644 --- a/lib/redis/namespace.rb +++ b/lib/redis/namespace.rb @@ -488,7 +488,14 @@ def rem_namespace(key) key.each { |k| yielder.yield rem_namespace(k) } end else - key.to_s.force_encoding("BINARY").sub(/\A#{@namespace}:/, '') + string_key = key.to_s.dup + if string_key.respond_to? :force_encoding + # force_encoding is not available in ruby 1.8.7 + rem_key = string_key.force_encoding('BINARY') + else + rem_key = string_key + end + rem_key.sub(/\A#{@namespace}:/, '') end end diff --git a/spec/redis_spec.rb b/spec/redis_spec.rb index 17ae64a..7ae837e 100644 --- a/spec/redis_spec.rb +++ b/spec/redis_spec.rb @@ -369,7 +369,17 @@ it "should not throw exception on invalid UTF-8 sequences in keys" do @namespaced.set("f\xFCo", 'bar') @namespaced.set("foo", 'bar') - @namespaced.keys.should eq ["f\xFCo", "foo"] + @namespaced.get("f\xFCo").should eq('bar') + keys = @namespaced.keys + # force_encoding is not available in ruby 1.8.7 + if "".respond_to? :force_encoding + keys.should eq ["f\xFCo".force_encoding('BINARY'), "foo"] + else + keys.should eq ["f\xFCo", "foo"] + end + keys.each do |k| + @namespaced.get(k).should eq('bar') + end end it "should respond to :namespace=" do From 6613e5c3dad49aa576f49e65c83012a2bd69165e Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Tue, 27 Jan 2015 14:54:20 -0800 Subject: [PATCH 4/4] ignore sort order when comparing array contents for encoding test --- spec/redis_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/redis_spec.rb b/spec/redis_spec.rb index 7ae837e..22ec375 100644 --- a/spec/redis_spec.rb +++ b/spec/redis_spec.rb @@ -370,12 +370,12 @@ @namespaced.set("f\xFCo", 'bar') @namespaced.set("foo", 'bar') @namespaced.get("f\xFCo").should eq('bar') - keys = @namespaced.keys + keys = @namespaced.keys.sort # force_encoding is not available in ruby 1.8.7 if "".respond_to? :force_encoding - keys.should eq ["f\xFCo".force_encoding('BINARY'), "foo"] + keys.should eq ["f\xFCo".force_encoding('BINARY'), "foo"].sort else - keys.should eq ["f\xFCo", "foo"] + keys.should eq ["f\xFCo", "foo"].sort end keys.each do |k| @namespaced.get(k).should eq('bar')