diff options
author | Christoffer Sawicki <christoffer.sawicki@gmail.com> | 2008-07-02 00:11:06 +0200 |
---|---|---|
committer | Christian Neukirchen <chneukirchen@gmail.com> | 2008-07-06 14:18:30 +0200 |
commit | a31ee950d37b123b8b32c792ab448bb57e707431 (patch) | |
tree | dead4b045d396fc514d57c8aa6f5e75c17cc1aab | |
parent | 0f2dab573bb53d612bd93cc04327bf147909fb95 (diff) | |
download | rack-a31ee950d37b123b8b32c792ab448bb57e707431.tar.gz |
Implemented Rack::Deflater
-rw-r--r-- | lib/rack.rb | 1 | ||||
-rw-r--r-- | lib/rack/deflater.rb | 44 | ||||
-rw-r--r-- | test/spec_rack_deflater.rb | 51 |
3 files changed, 96 insertions, 0 deletions
diff --git a/lib/rack.rb b/lib/rack.rb index 607d0f5c..933f5dcb 100644 --- a/lib/rack.rb +++ b/lib/rack.rb @@ -30,6 +30,7 @@ module Rack autoload :Cascade, "rack/cascade" autoload :CommonLogger, "rack/commonlogger" autoload :File, "rack/file" + autoload :Deflater, "rack/deflater" autoload :Directory, "rack/directory" autoload :ForwardRequest, "rack/recursive" autoload :Handler, "rack/handler" diff --git a/lib/rack/deflater.rb b/lib/rack/deflater.rb new file mode 100644 index 00000000..72ba3ed4 --- /dev/null +++ b/lib/rack/deflater.rb @@ -0,0 +1,44 @@ +require "zlib" + +module Rack + +class Deflater + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + + request = Request.new(env) + encoding = Utils.select_best_encoding(%w(deflate identity), request.accept_encoding) + + case encoding + when "deflate" + [status, headers.merge("Content-Encoding" => "deflate"), self.class.deflate(body)] + when "identity" + [status, headers, body] + when nil + # TODO: Add Content-Type + [406, {}, "..."] + end + end + + # Loosely based on Mongrel's Deflate handler + def self.deflate(body) + deflater = Zlib::Deflate.new( + Zlib::DEFAULT_COMPRESSION, + # drop the zlib header which causes both Safari and IE to choke + -Zlib::MAX_WBITS, + Zlib::DEF_MEM_LEVEL, + Zlib::DEFAULT_STRATEGY) + + # TODO: Add streaming + # TODO: Consider all part types + body.each { |part| deflater << part } + + return deflater.finish + end +end + +end diff --git a/test/spec_rack_deflater.rb b/test/spec_rack_deflater.rb new file mode 100644 index 00000000..7fc1c808 --- /dev/null +++ b/test/spec_rack_deflater.rb @@ -0,0 +1,51 @@ +require 'test/spec' + +require 'rack/mock' +require 'rack/deflater' +require 'stringio' + +context "Rack::Deflater" do + def build_response(body, accept_encoding) + app = lambda { |env| [200, {}, body] } + request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => accept_encoding) + response = Rack::Deflater.new(app).call(request) + + return response + end + + specify "should be able to deflate bodies that respond to each" do + body = Object.new + class << body; def each; yield("foo"); yield("bar"); end; end + + response = build_response(body, "deflate") + + response[0].should.equal(200) + response[1].should.equal({ "Content-Encoding" => "deflate" }) + response[2].to_s.should.equal("K\313\317OJ,\002\000") + end + + # TODO: This is really just a special case of the above... + specify "should be able to deflate String bodies" do + response = build_response("Hello world!", "deflate") + + response[0].should.equal(200) + response[1].should.equal({ "Content-Encoding" => "deflate" }) + response[2].to_s.should.equal("\363H\315\311\311W(\317/\312IQ\004\000") + end + + specify "should be able to fallback to no deflation" do + response = build_response("Hello world!", "superzip") + + response[0].should.equal(200) + response[1].should.equal({}) + response[2].should.equal("Hello world!") + end + + specify "should handle the lack of an acceptable encoding" do + response = build_response("Hello world!", "identity;q=0") + + response[0].should.equal(406) + response[1].should.equal({}) + # response[2].should.equal("...") + end +end |