summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoffer Sawicki <christoffer.sawicki@gmail.com>2008-07-01 22:37:58 +0200
committerChristian Neukirchen <chneukirchen@gmail.com>2008-07-06 14:18:30 +0200
commit0f2dab573bb53d612bd93cc04327bf147909fb95 (patch)
tree4417c09b6a086add98cbc2e24a3dbf8864a9efab
parent835cfd6860864d0d0d559b3e997544aeb374dc00 (diff)
downloadrack-0f2dab573bb53d612bd93cc04327bf147909fb95.tar.gz
Added support for Accept-Encoding (via Request#accept_encoding and Utils.select_best_encoding)
-rw-r--r--lib/rack/request.rb12
-rw-r--r--lib/rack/utils.rb30
-rw-r--r--test/spec_rack_request.rb16
-rw-r--r--test/spec_rack_utils.rb23
4 files changed, 81 insertions, 0 deletions
diff --git a/lib/rack/request.rb b/lib/rack/request.rb
index 68c11198..2a9bcc15 100644
--- a/lib/rack/request.rb
+++ b/lib/rack/request.rb
@@ -193,5 +193,17 @@ module Rack
path << "?" << query_string unless query_string.empty?
path
end
+
+ def accept_encoding
+ @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part|
+ m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick
+
+ if m
+ [m[1], (m[2] || 1.0).to_f]
+ else
+ raise "Invalid value for Accept-Encoding: #{part.inspect}"
+ end
+ end
+ end
end
end
diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb
index 4329b988..25254bbd 100644
--- a/lib/rack/utils.rb
+++ b/lib/rack/utils.rb
@@ -71,6 +71,36 @@ module Rack
end
module_function :escape_html
+ def select_best_encoding(available_encodings, accept_encoding)
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
+
+ expanded_accept_encoding =
+ accept_encoding.map { |m, q|
+ if m == "*"
+ (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] }
+ else
+ [[m, q]]
+ end
+ }.inject([]) { |mem, list|
+ mem + list
+ }
+
+ encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m }
+
+ unless encoding_candidates.include?("identity")
+ encoding_candidates.push("identity")
+ end
+
+ expanded_accept_encoding.find_all { |m, q|
+ q == 0.0
+ }.each { |m, _|
+ encoding_candidates.delete(m)
+ }
+
+ return (encoding_candidates & available_encodings)[0]
+ end
+ module_function :select_best_encoding
+
# The recommended manner in which to implement a contexting application
# is to define a method #context in which a new Context is instantiated.
#
diff --git a/test/spec_rack_request.rb b/test/spec_rack_request.rb
index 4321516e..2b30ff3f 100644
--- a/test/spec_rack_request.rb
+++ b/test/spec_rack_request.rb
@@ -381,4 +381,20 @@ EOF
res.should.be.ok
end
+
+ specify "should parse Accept-Encoding correctly" do
+ parser = lambda do |x|
+ Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding
+ end
+
+ parser.call(nil).should.equal([])
+
+ parser.call("compress, gzip").should.equal([["compress", 1.0], ["gzip", 1.0]])
+ parser.call("").should.equal([])
+ parser.call("*").should.equal([["*", 1.0]])
+ parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]])
+ parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ])
+
+ lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
+ end
end
diff --git a/test/spec_rack_utils.rb b/test/spec_rack_utils.rb
index 8256e12f..6e253c43 100644
--- a/test/spec_rack_utils.rb
+++ b/test/spec_rack_utils.rb
@@ -39,6 +39,29 @@ context "Rack::Utils" do
Rack::Utils.build_query("my weird field" => "q1!2\"'w$5&7/z8)?").
should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F"
end
+
+ specify "should figure out which encodings are acceptable" do
+ helper = lambda do |a, b|
+ request = Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
+ Rack::Utils.select_best_encoding(a, b)
+ end
+
+ helper.call(%w(), [["x", 1]]).should.equal(nil)
+ helper.call(%w(identity), [["identity", 0.0]]).should.equal(nil)
+ helper.call(%w(identity), [["*", 0.0]]).should.equal(nil)
+
+ helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("identity")
+
+ helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("compress")
+ helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).should.equal("gzip")
+
+ helper.call(%w(foo bar identity), []).should.equal("identity")
+ helper.call(%w(foo bar identity), [["*", 1.0]]).should.equal("foo")
+ helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).should.equal("bar")
+
+ helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).should.equal("identity")
+ helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
+ end
end
context "Rack::Utils::HeaderHash" do