diff options
author | Christoffer Sawicki <christoffer.sawicki@gmail.com> | 2008-07-01 22:37:58 +0200 |
---|---|---|
committer | Christian Neukirchen <chneukirchen@gmail.com> | 2008-07-06 14:18:30 +0200 |
commit | 0f2dab573bb53d612bd93cc04327bf147909fb95 (patch) | |
tree | 4417c09b6a086add98cbc2e24a3dbf8864a9efab | |
parent | 835cfd6860864d0d0d559b3e997544aeb374dc00 (diff) | |
download | rack-0f2dab573bb53d612bd93cc04327bf147909fb95.tar.gz |
Added support for Accept-Encoding (via Request#accept_encoding and Utils.select_best_encoding)
-rw-r--r-- | lib/rack/request.rb | 12 | ||||
-rw-r--r-- | lib/rack/utils.rb | 30 | ||||
-rw-r--r-- | test/spec_rack_request.rb | 16 | ||||
-rw-r--r-- | test/spec_rack_utils.rb | 23 |
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 |