Skip to content

Commit

Permalink
Non-normalizing HeaderHash with case-insensitive lookups
Browse files Browse the repository at this point in the history
This is a backwards incompatible change that removes header name
normalization while attempting to keep most of its benefits. The
header name case is preserved but the Hash has case insensitive
lookup, replace, delete, and include semantics.
  • Loading branch information
rtomayko committed Dec 30, 2008
1 parent 5db554e commit 4e17443
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 23 deletions.
19 changes: 15 additions & 4 deletions lib/rack/utils.rb
Expand Up @@ -159,6 +159,7 @@ def pretty_print pp
# A case-normalizing Hash, adjusting on [] and []=.
class HeaderHash < Hash
def initialize(hash={})
@names = {}
hash.each { |k, v| self[k] = v }
end

Expand All @@ -167,16 +168,26 @@ def to_hash
end

def [](k)
super capitalize(k)
super @names[k.downcase]
end

def []=(k, v)
super capitalize(k), v
delete k
@names[k.downcase] = k
super k, v
end

def capitalize(k)
k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }
def delete(k)
super @names.delete(k.downcase)
end

def include?(k)
@names.has_key? k.downcase
end

alias_method :has_key?, :include?
alias_method :member?, :include?
alias_method :key?, :include?
end

# Every standard HTTP code mapped to the appropriate message.
Expand Down
34 changes: 15 additions & 19 deletions test/spec_rack_utils.rb
Expand Up @@ -65,28 +65,24 @@
end

context "Rack::Utils::HeaderHash" do
specify "should capitalize on all accesses" do
h = Rack::Utils::HeaderHash.new("foo" => "bar")
h["foo"].should.equal "bar"
h["Foo"].should.equal "bar"
h["FOO"].should.equal "bar"

h.to_hash.should.equal "Foo" => "bar"

h["bar-zzle"] = "quux"

h.to_hash.should.equal "Foo" => "bar", "Bar-Zzle" => "quux"
specify "should retain header case" do
h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
h['ETag'] = 'Boo!'
h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
end

specify "should capitalize correctly" do
h = Rack::Utils::HeaderHash.new
specify "should check existence of keys case insensitively" do
h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
h.should.include 'content-md5'
h.should.not.include 'ETag'
end

h.capitalize("foo").should.equal "Foo"
h.capitalize("foo-bar").should.equal "Foo-Bar"
h.capitalize("foo_bar").should.equal "Foo_Bar"
h.capitalize("foo bar").should.equal "Foo Bar"
h.capitalize("foo-bar-quux").should.equal "Foo-Bar-Quux"
h.capitalize("foo-bar-2quux").should.equal "Foo-Bar-2quux"
specify "should overwrite case insensitively and assume the new key's case" do
h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
h["foo-bar"] = "bizzle"
h["FOO-BAR"].should.equal "bizzle"
h.length.should.equal 1
h.to_hash.should.equal "foo-bar" => "bizzle"
end

specify "should be converted to real Hash" do
Expand Down

0 comments on commit 4e17443

Please sign in to comment.